From 2a62fb4a2d9b9248aa15bba9c89d75a7ddc8cfc6 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Thu, 19 Jan 2023 22:34:15 +0100 Subject: [PATCH 001/133] Improve TransparentUpgradeableProxy's transparency (#3977) Co-authored-by: Francisco --- .changeset/many-panthers-hide.md | 5 +++++ .../mocks/proxy/ClashingImplementation.sol | 7 +++---- .../TransparentUpgradeableProxy.sol | 20 +++++++++++++++---- .../TransparentUpgradeableProxy.behaviour.js | 15 +++++++++++--- 4 files changed, 36 insertions(+), 11 deletions(-) create mode 100644 .changeset/many-panthers-hide.md diff --git a/.changeset/many-panthers-hide.md b/.changeset/many-panthers-hide.md new file mode 100644 index 000000000..5f04c99df --- /dev/null +++ b/.changeset/many-panthers-hide.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': minor +--- + +`TransparentUpgradeableProxy`: support value passthrough for all ifAdmin function. diff --git a/contracts/mocks/proxy/ClashingImplementation.sol b/contracts/mocks/proxy/ClashingImplementation.sol index 80aca0c29..5c272a89d 100644 --- a/contracts/mocks/proxy/ClashingImplementation.sol +++ b/contracts/mocks/proxy/ClashingImplementation.sol @@ -3,12 +3,11 @@ pragma solidity ^0.8.0; /** - * @dev Implementation contract with an admin() function made to clash with - * @dev TransparentUpgradeableProxy's to test correct functioning of the - * @dev Transparent Proxy feature. + * @dev Implementation contract with a payable admin() function made to clash with TransparentUpgradeableProxy's to + * test correct functioning of the Transparent Proxy feature. */ contract ClashingImplementation { - function admin() external pure returns (address) { + function admin() external payable returns (address) { return 0x0000000000000000000000000000000011111142; } diff --git a/contracts/proxy/transparent/TransparentUpgradeableProxy.sol b/contracts/proxy/transparent/TransparentUpgradeableProxy.sol index 3685360e7..155a22e01 100644 --- a/contracts/proxy/transparent/TransparentUpgradeableProxy.sol +++ b/contracts/proxy/transparent/TransparentUpgradeableProxy.sol @@ -55,7 +55,8 @@ contract TransparentUpgradeableProxy is ERC1967Proxy { * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103` */ - function admin() external ifAdmin returns (address admin_) { + function admin() external payable ifAdmin returns (address admin_) { + _requireZeroValue(); admin_ = _getAdmin(); } @@ -68,7 +69,8 @@ contract TransparentUpgradeableProxy is ERC1967Proxy { * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc` */ - function implementation() external ifAdmin returns (address implementation_) { + function implementation() external payable ifAdmin returns (address implementation_) { + _requireZeroValue(); implementation_ = _implementation(); } @@ -79,7 +81,8 @@ contract TransparentUpgradeableProxy is ERC1967Proxy { * * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}. */ - function changeAdmin(address newAdmin) external virtual ifAdmin { + function changeAdmin(address newAdmin) external payable virtual ifAdmin { + _requireZeroValue(); _changeAdmin(newAdmin); } @@ -88,7 +91,8 @@ contract TransparentUpgradeableProxy is ERC1967Proxy { * * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}. */ - function upgradeTo(address newImplementation) external ifAdmin { + function upgradeTo(address newImplementation) external payable ifAdmin { + _requireZeroValue(); _upgradeToAndCall(newImplementation, bytes(""), false); } @@ -117,4 +121,12 @@ contract TransparentUpgradeableProxy is ERC1967Proxy { require(msg.sender != _getAdmin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target"); super._beforeFallback(); } + + /** + * @dev To keep this contract fully transparent, all `ifAdmin` functions must be payable. This helper is here to + * emulate some proxy functions being non-payable while still allowing value to pass through. + */ + function _requireZeroValue() private { + require(msg.value == 0); + } } diff --git a/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js b/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js index da8f21bee..3a10357a9 100644 --- a/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js +++ b/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js @@ -330,14 +330,23 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy(createProx ); }); - context('when function names clash', function () { + describe('when function names clash', function () { it('when sender is proxy admin should run the proxy function', async function () { - const value = await this.proxy.admin.call({ from: proxyAdminAddress }); + const value = await this.proxy.admin.call({ from: proxyAdminAddress, value: 0 }); expect(value).to.be.equal(proxyAdminAddress); }); it('when sender is other should delegate to implementation', async function () { - const value = await this.proxy.admin.call({ from: anotherAccount }); + const value = await this.proxy.admin.call({ from: anotherAccount, value: 0 }); + expect(value).to.be.equal('0x0000000000000000000000000000000011111142'); + }); + + it('when sender is proxy admin value should not be accepted', async function () { + await expectRevert.unspecified(this.proxy.admin.call({ from: proxyAdminAddress, value: 1 })); + }); + + it('when sender is other value should be accepted', async function () { + const value = await this.proxy.admin.call({ from: anotherAccount, value: 1 }); expect(value).to.be.equal('0x0000000000000000000000000000000011111142'); }); }); From c404862cba658deae081a9e437942a241eee78c0 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Thu, 19 Jan 2023 23:00:53 +0100 Subject: [PATCH 002/133] Use oz-upgrades-unsafe-allow-reachable in ERC1967Upgrade (#3971) Co-authored-by: Francisco --- .changeset/strong-bulldogs-buy.md | 5 +++++ .changeset/yellow-swans-cover.md | 5 +++++ contracts/proxy/ERC1967/ERC1967Upgrade.sol | 2 -- contracts/proxy/utils/UUPSUpgradeable.sol | 4 ++++ 4 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 .changeset/strong-bulldogs-buy.md create mode 100644 .changeset/yellow-swans-cover.md diff --git a/.changeset/strong-bulldogs-buy.md b/.changeset/strong-bulldogs-buy.md new file mode 100644 index 000000000..001b0f88f --- /dev/null +++ b/.changeset/strong-bulldogs-buy.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': minor +--- + +`ERC1967Upgrade`: removed contract-wide `oz-upgrades-unsafe-allow delegatecall` annotation, replaced by granular annotation in `UUPSUpgradeable`. diff --git a/.changeset/yellow-swans-cover.md b/.changeset/yellow-swans-cover.md new file mode 100644 index 000000000..ee1680178 --- /dev/null +++ b/.changeset/yellow-swans-cover.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': minor +--- + +`UUPSUpgradeable`: added granular `oz-upgrades-unsafe-allow-reachable` annotation to improve upgrade safety checks on latest version of the Upgrades Plugins (starting with `@openzeppelin/upgrades-core@1.21.0`). diff --git a/contracts/proxy/ERC1967/ERC1967Upgrade.sol b/contracts/proxy/ERC1967/ERC1967Upgrade.sol index 0f32d4d23..0680f3549 100644 --- a/contracts/proxy/ERC1967/ERC1967Upgrade.sol +++ b/contracts/proxy/ERC1967/ERC1967Upgrade.sol @@ -13,8 +13,6 @@ import "../../utils/StorageSlot.sol"; * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. * * _Available since v4.1._ - * - * @custom:oz-upgrades-unsafe-allow delegatecall */ abstract contract ERC1967Upgrade { // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1 diff --git a/contracts/proxy/utils/UUPSUpgradeable.sol b/contracts/proxy/utils/UUPSUpgradeable.sol index 8b7366328..bb696f6fa 100644 --- a/contracts/proxy/utils/UUPSUpgradeable.sol +++ b/contracts/proxy/utils/UUPSUpgradeable.sol @@ -62,6 +62,8 @@ abstract contract UUPSUpgradeable is IERC1822Proxiable, ERC1967Upgrade { * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. + * + * @custom:oz-upgrades-unsafe-allow-reachable delegatecall */ function upgradeTo(address newImplementation) external virtual onlyProxy { _authorizeUpgrade(newImplementation); @@ -75,6 +77,8 @@ abstract contract UUPSUpgradeable is IERC1822Proxiable, ERC1967Upgrade { * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. + * + * @custom:oz-upgrades-unsafe-allow-reachable delegatecall */ function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual onlyProxy { _authorizeUpgrade(newImplementation); From b1c2c43d6af6adf0b0a74cc77683b1d13d66e8bc Mon Sep 17 00:00:00 2001 From: Vittorio Minacori Date: Mon, 23 Jan 2023 11:30:11 +0100 Subject: [PATCH 003/133] Lint should not override files (#3988) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 45db40433..b4035b820 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "lint:fix": "npm run lint:js:fix && npm run lint:sol:fix", "lint:js": "prettier --loglevel warn --ignore-path .gitignore '**/*.{js,ts}' --check && eslint --ignore-path .gitignore .", "lint:js:fix": "prettier --loglevel warn --ignore-path .gitignore '**/*.{js,ts}' --write && eslint --ignore-path .gitignore . --fix", - "lint:sol": "prettier --loglevel warn --ignore-path .gitignore '{contracts,test}/**/*.sol' --write && solhint '{contracts,test}/**/*.sol'", + "lint:sol": "prettier --loglevel warn --ignore-path .gitignore '{contracts,test}/**/*.sol' --check && solhint '{contracts,test}/**/*.sol'", "lint:sol:fix": "prettier --loglevel warn --ignore-path .gitignore '{contracts,test}/**/*.sol' --write", "clean": "hardhat clean && rimraf build contracts/build", "prepare": "scripts/prepare.sh", From a34dd8bb1b8e941f6e7f65c58df0b3b994afbc16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Garc=C3=ADa?= Date: Tue, 24 Jan 2023 15:00:03 -0600 Subject: [PATCH 004/133] Add `solidity` language to missing code snippets (#3992) --- GUIDELINES.md | 6 +++--- contracts/access/AccessControl.sol | 4 ++-- contracts/proxy/utils/Initializable.sol | 3 ++- contracts/utils/StorageSlot.sol | 2 +- contracts/utils/structs/DoubleEndedQueue.sol | 2 +- contracts/utils/structs/EnumerableMap.sol | 2 +- contracts/utils/structs/EnumerableSet.sol | 2 +- scripts/generate/templates/EnumerableMap.js | 2 +- scripts/generate/templates/EnumerableSet.js | 2 +- 9 files changed, 13 insertions(+), 12 deletions(-) diff --git a/GUIDELINES.md b/GUIDELINES.md index cdeddb90c..bac94be6f 100644 --- a/GUIDELINES.md +++ b/GUIDELINES.md @@ -72,7 +72,7 @@ In addition to the official Solidity Style Guide we have a number of other conve * Internal or private state variables or functions should have an underscore prefix. - ``` + ```solidity contract TestContract { uint256 private _privateVar; uint256 internal _internalVar; @@ -84,7 +84,7 @@ In addition to the official Solidity Style Guide we have a number of other conve * Events should be emitted immediately after the state change that they represent, and should be named in the past tense. - ``` + ```solidity function _burn(address who, uint256 value) internal { super._burn(who, value); emit TokensBurned(who, value); @@ -96,7 +96,7 @@ In addition to the official Solidity Style Guide we have a number of other conve * Interface names should have a capital I prefix. - ``` + ```solidity interface IERC777 { ``` diff --git a/contracts/access/AccessControl.sol b/contracts/access/AccessControl.sol index 386b85c03..5f2829e74 100644 --- a/contracts/access/AccessControl.sol +++ b/contracts/access/AccessControl.sol @@ -19,14 +19,14 @@ import "../utils/introspection/ERC165.sol"; * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * - * ``` + * ```solidity * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * - * ``` + * ```solidity * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... diff --git a/contracts/proxy/utils/Initializable.sol b/contracts/proxy/utils/Initializable.sol index b454b5d95..638dbe353 100644 --- a/contracts/proxy/utils/Initializable.sol +++ b/contracts/proxy/utils/Initializable.sol @@ -18,12 +18,13 @@ import "../../utils/Address.sol"; * For example: * * [.hljs-theme-light.nopadding] - * ``` + * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } + * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); diff --git a/contracts/utils/StorageSlot.sol b/contracts/utils/StorageSlot.sol index 6ab8f5dc6..d23363bd6 100644 --- a/contracts/utils/StorageSlot.sol +++ b/contracts/utils/StorageSlot.sol @@ -12,7 +12,7 @@ pragma solidity ^0.8.0; * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC1967 implementation slot: - * ``` + * ```solidity * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * diff --git a/contracts/utils/structs/DoubleEndedQueue.sol b/contracts/utils/structs/DoubleEndedQueue.sol index eae79ada7..6b3ea70e3 100644 --- a/contracts/utils/structs/DoubleEndedQueue.sol +++ b/contracts/utils/structs/DoubleEndedQueue.sol @@ -12,7 +12,7 @@ import "../math/SafeCast.sol"; * * The struct is called `Bytes32Deque`. Other types can be cast to and from `bytes32`. This data structure can only be * used in storage, and not in memory. - * ``` + * ```solidity * DoubleEndedQueue.Bytes32Deque queue; * ``` * diff --git a/contracts/utils/structs/EnumerableMap.sol b/contracts/utils/structs/EnumerableMap.sol index 8b188c734..fb21f02cf 100644 --- a/contracts/utils/structs/EnumerableMap.sol +++ b/contracts/utils/structs/EnumerableMap.sol @@ -17,7 +17,7 @@ import "./EnumerableSet.sol"; * (O(1)). * - Entries are enumerated in O(n). No guarantees are made on the ordering. * - * ``` + * ```solidity * contract Example { * // Add the library methods * using EnumerableMap for EnumerableMap.UintToAddressMap; diff --git a/contracts/utils/structs/EnumerableSet.sol b/contracts/utils/structs/EnumerableSet.sol index 4c701c26c..a01f82d41 100644 --- a/contracts/utils/structs/EnumerableSet.sol +++ b/contracts/utils/structs/EnumerableSet.sol @@ -15,7 +15,7 @@ pragma solidity ^0.8.0; * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * - * ``` + * ```solidity * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; diff --git a/scripts/generate/templates/EnumerableMap.js b/scripts/generate/templates/EnumerableMap.js index dbd502a0b..2bbb69e3e 100644 --- a/scripts/generate/templates/EnumerableMap.js +++ b/scripts/generate/templates/EnumerableMap.js @@ -25,7 +25,7 @@ import "./EnumerableSet.sol"; * (O(1)). * - Entries are enumerated in O(n). No guarantees are made on the ordering. * - * \`\`\` + * \`\`\`solidity * contract Example { * // Add the library methods * using EnumerableMap for EnumerableMap.UintToAddressMap; diff --git a/scripts/generate/templates/EnumerableSet.js b/scripts/generate/templates/EnumerableSet.js index a3af2c304..2b6a9c64d 100644 --- a/scripts/generate/templates/EnumerableSet.js +++ b/scripts/generate/templates/EnumerableSet.js @@ -22,7 +22,7 @@ pragma solidity ^0.8.0; * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * - * \`\`\` + * \`\`\`solidity * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; From a284569a7c611423d1d12d826d67db6d9967923c Mon Sep 17 00:00:00 2001 From: Pascal Marco Caversaccio Date: Wed, 25 Jan 2023 14:54:51 +0100 Subject: [PATCH 005/133] Rename `ERC20ReturnFalseMock copy.sol` to `ERC20ReturnFalseMock.sol` (#4000) --- .../{ERC20ReturnFalseMock copy.sol => ERC20ReturnFalseMock.sol} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename contracts/mocks/token/{ERC20ReturnFalseMock copy.sol => ERC20ReturnFalseMock.sol} (100%) diff --git a/contracts/mocks/token/ERC20ReturnFalseMock copy.sol b/contracts/mocks/token/ERC20ReturnFalseMock.sol similarity index 100% rename from contracts/mocks/token/ERC20ReturnFalseMock copy.sol rename to contracts/mocks/token/ERC20ReturnFalseMock.sol From 69c8d1010e1ca53ce3fa7f6fddff96759aec87e1 Mon Sep 17 00:00:00 2001 From: blockeater Date: Thu, 26 Jan 2023 00:46:34 +0500 Subject: [PATCH 006/133] Make upgradeTo and upgradeToAndCall public (#3959) Co-authored-by: Francisco --- .changeset/five-ducks-develop.md | 5 +++++ contracts/mocks/proxy/UUPSLegacy.sol | 4 ++-- contracts/mocks/proxy/UUPSUpgradeableMock.sol | 4 ++-- contracts/proxy/utils/UUPSUpgradeable.sol | 4 ++-- 4 files changed, 11 insertions(+), 6 deletions(-) create mode 100644 .changeset/five-ducks-develop.md diff --git a/.changeset/five-ducks-develop.md b/.changeset/five-ducks-develop.md new file mode 100644 index 000000000..fe25db071 --- /dev/null +++ b/.changeset/five-ducks-develop.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': patch +--- + +`UUPSUpgradeable.sol`: Change visibility to the functions `upgradeTo ` and `upgradeToAndCall ` from `external` to `public`. diff --git a/contracts/mocks/proxy/UUPSLegacy.sol b/contracts/mocks/proxy/UUPSLegacy.sol index 7a3002889..6956f5675 100644 --- a/contracts/mocks/proxy/UUPSLegacy.sol +++ b/contracts/mocks/proxy/UUPSLegacy.sol @@ -44,11 +44,11 @@ contract UUPSUpgradeableLegacyMock is UUPSUpgradeableMock { } // hooking into the old mechanism - function upgradeTo(address newImplementation) external override { + function upgradeTo(address newImplementation) public override { _upgradeToAndCallSecureLegacyV1(newImplementation, bytes(""), false); } - function upgradeToAndCall(address newImplementation, bytes memory data) external payable override { + function upgradeToAndCall(address newImplementation, bytes memory data) public payable override { _upgradeToAndCallSecureLegacyV1(newImplementation, data, false); } } diff --git a/contracts/mocks/proxy/UUPSUpgradeableMock.sol b/contracts/mocks/proxy/UUPSUpgradeableMock.sol index deb20a000..f02271c49 100644 --- a/contracts/mocks/proxy/UUPSUpgradeableMock.sol +++ b/contracts/mocks/proxy/UUPSUpgradeableMock.sol @@ -23,11 +23,11 @@ contract UUPSUpgradeableMock is NonUpgradeableMock, UUPSUpgradeable { } contract UUPSUpgradeableUnsafeMock is UUPSUpgradeableMock { - function upgradeTo(address newImplementation) external override { + function upgradeTo(address newImplementation) public override { ERC1967Upgrade._upgradeToAndCall(newImplementation, bytes(""), false); } - function upgradeToAndCall(address newImplementation, bytes memory data) external payable override { + function upgradeToAndCall(address newImplementation, bytes memory data) public payable override { ERC1967Upgrade._upgradeToAndCall(newImplementation, data, false); } } diff --git a/contracts/proxy/utils/UUPSUpgradeable.sol b/contracts/proxy/utils/UUPSUpgradeable.sol index bb696f6fa..4ff026638 100644 --- a/contracts/proxy/utils/UUPSUpgradeable.sol +++ b/contracts/proxy/utils/UUPSUpgradeable.sol @@ -65,7 +65,7 @@ abstract contract UUPSUpgradeable is IERC1822Proxiable, ERC1967Upgrade { * * @custom:oz-upgrades-unsafe-allow-reachable delegatecall */ - function upgradeTo(address newImplementation) external virtual onlyProxy { + function upgradeTo(address newImplementation) public virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, new bytes(0), false); } @@ -80,7 +80,7 @@ abstract contract UUPSUpgradeable is IERC1822Proxiable, ERC1967Upgrade { * * @custom:oz-upgrades-unsafe-allow-reachable delegatecall */ - function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual onlyProxy { + function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, data, true); } From d6fb3d645ff46f059745935b62fcc32c63cf4034 Mon Sep 17 00:00:00 2001 From: Francisco Date: Thu, 26 Jan 2023 14:17:18 -0300 Subject: [PATCH 007/133] Add guidelines for pull requests (#4002) --- GUIDELINES.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/GUIDELINES.md b/GUIDELINES.md index bac94be6f..0f4c9829e 100644 --- a/GUIDELINES.md +++ b/GUIDELINES.md @@ -62,6 +62,20 @@ Some other examples of automation are: - Looking for common security vulnerabilities or errors in our code (eg. reentrancy analysis). - Keeping dependencies up to date and monitoring for vulnerable dependencies. +## Pull requests + +Pull requests are squash-merged to keep the `master` branch history clean. The title of the pull request becomes the commit message, so it should be written in a consistent format: + +1) Begin with a capital letter. +2) Do not end with a period. +3) Write in the imperative: "Add feature X" and not "Adds feature X" or "Added feature X". + +This repository does not follow conventional commits, so do not prefix the title with "fix:" or "feat:". + +Work in progress pull requests should be submitted as Drafts and should not be prefixed with "WIP:". + +Branch names don't matter, and commit messages within a pull request mostly don't matter either, although they can help the review process. + # Solidity Conventions In addition to the official Solidity Style Guide we have a number of other conventions that must be followed. From 0320a718e8e07b1d932f5acb8ad9cec9d9eed99b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Garc=C3=ADa?= Date: Thu, 26 Jan 2023 11:38:34 -0600 Subject: [PATCH 008/133] Fix Governance docs reference to blocktime (#3994) --- 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 aa27c0ba8..d59e3ce9f 100644 --- a/docs/modules/ROOT/pages/governance.adoc +++ b/docs/modules/ROOT/pages/governance.adoc @@ -137,7 +137,7 @@ votingDelay: How long after a proposal is created should voting power be fixed. votingPeriod: How long does a proposal remain open to votes. -These parameters are specified in number of blocks. Assuming block time of around 13.14 seconds, we will set votingDelay = 1 day = 6570 blocks, and votingPeriod = 1 week = 45992 blocks. +These parameters are specified in number of blocks. Assuming block time of around 12 seconds, we will set votingDelay = 1 day = 7200 blocks, and votingPeriod = 1 week = 50400 blocks. We can optionally set a proposal threshold as well. This restricts proposal creation to accounts who have enough voting power. From 5e28952cbdc0eb7d19ee62580ab31b30c2376e48 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Thu, 26 Jan 2023 20:46:11 +0100 Subject: [PATCH 009/133] Add a public Governor.cancel function (#3983) --- .changeset/flat-deers-end.md | 5 + contracts/governance/Governor.sol | 30 +++- contracts/governance/IGovernor.sol | 8 ++ .../GovernorCompatibilityBravo.sol | 9 +- .../IGovernorCompatibilityBravo.sol | 5 - .../GovernorCompatibilityBravoMock.sol | 4 + contracts/mocks/wizard/MyGovernor3.sol | 4 + test/governance/Governor.test.js | 128 +++++++++++++----- .../GovernorCompatibilityBravo.test.js | 6 +- .../GovernorTimelockCompound.test.js | 4 +- .../GovernorTimelockControl.test.js | 4 +- test/helpers/governance.js | 13 +- 12 files changed, 157 insertions(+), 63 deletions(-) create mode 100644 .changeset/flat-deers-end.md diff --git a/.changeset/flat-deers-end.md b/.changeset/flat-deers-end.md new file mode 100644 index 000000000..61895f2cf --- /dev/null +++ b/.changeset/flat-deers-end.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': minor +--- + +`Governor`: add a public `cancel(uint256)` function. diff --git a/contracts/governance/Governor.sol b/contracts/governance/Governor.sol index 8235fb5ec..f82f9fea8 100644 --- a/contracts/governance/Governor.sol +++ b/contracts/governance/Governor.sol @@ -40,6 +40,7 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor, IERC721Receive Timers.BlockNumber voteEnd; bool executed; bool canceled; + address proposer; } string private _name; @@ -95,9 +96,11 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor, IERC721Receive return interfaceId == (type(IGovernor).interfaceId ^ + this.cancel.selector ^ this.castVoteWithReasonAndParams.selector ^ this.castVoteWithReasonAndParamsBySig.selector ^ this.getVotesWithParams.selector) || + interfaceId == (type(IGovernor).interfaceId ^ this.cancel.selector) || interfaceId == type(IGovernor).interfaceId || interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId); @@ -248,8 +251,10 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor, IERC721Receive bytes[] memory calldatas, string memory description ) public virtual override returns (uint256) { + address proposer = _msgSender(); + require( - getVotes(_msgSender(), block.number - 1) >= proposalThreshold(), + getVotes(proposer, block.number - 1) >= proposalThreshold(), "Governor: proposer votes below proposal threshold" ); @@ -267,10 +272,11 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor, IERC721Receive proposal.voteStart.setDeadline(snapshot); proposal.voteEnd.setDeadline(deadline); + proposal.proposer = proposer; emit ProposalCreated( proposalId, - _msgSender(), + proposer, targets, values, new string[](targets.length), @@ -310,6 +316,15 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor, IERC721Receive return proposalId; } + /** + * @dev See {IGovernor-cancel}. + */ + function cancel(uint256 proposalId) public virtual override { + require(state(proposalId) == ProposalState.Pending, "Governor: too late to cancel"); + require(_msgSender() == _proposals[proposalId].proposer, "Governor: only proposer can cancel"); + _cancel(proposalId); + } + /** * @dev Internal execution mechanism. Can be overridden to implement different execution mechanism */ @@ -375,7 +390,16 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor, IERC721Receive bytes[] memory calldatas, bytes32 descriptionHash ) internal virtual returns (uint256) { - uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash); + return _cancel(hashProposal(targets, values, calldatas, descriptionHash)); + } + + /** + * @dev Internal cancel mechanism: locks up the proposal timer, preventing it from being re-submitted. Marks it as + * canceled to allow distinguishing it from executed proposals. + * + * Emits a {IGovernor-ProposalCanceled} event. + */ + function _cancel(uint256 proposalId) internal virtual returns (uint256) { ProposalState status = state(proposalId); require( diff --git a/contracts/governance/IGovernor.sol b/contracts/governance/IGovernor.sol index eb3d1fc05..18cf57fb1 100644 --- a/contracts/governance/IGovernor.sol +++ b/contracts/governance/IGovernor.sol @@ -216,6 +216,14 @@ abstract contract IGovernor is IERC165 { bytes32 descriptionHash ) public payable virtual returns (uint256 proposalId); + /** + * @dev Cancel a proposal. This is restricted to Pending proposal (before the vote starts) and is restricted to + * the proposal's proposer. + * + * Emits a {ProposalCanceled} event. + */ + function cancel(uint256 proposalId) public virtual; + /** * @dev Cast a vote * diff --git a/contracts/governance/compatibility/GovernorCompatibilityBravo.sol b/contracts/governance/compatibility/GovernorCompatibilityBravo.sol index 8d74742c5..912d02f8a 100644 --- a/contracts/governance/compatibility/GovernorCompatibilityBravo.sol +++ b/contracts/governance/compatibility/GovernorCompatibilityBravo.sol @@ -99,7 +99,7 @@ abstract contract GovernorCompatibilityBravo is IGovernorTimelock, IGovernorComp ); } - function cancel(uint256 proposalId) public virtual override { + function cancel(uint256 proposalId) public virtual override(IGovernor, Governor) { ProposalDetails storage details = _proposalDetails[proposalId]; require( @@ -107,12 +107,7 @@ abstract contract GovernorCompatibilityBravo is IGovernorTimelock, IGovernorComp "GovernorBravo: proposer above threshold" ); - _cancel( - details.targets, - details.values, - _encodeCalldata(details.signatures, details.calldatas), - details.descriptionHash - ); + _cancel(proposalId); } /** diff --git a/contracts/governance/compatibility/IGovernorCompatibilityBravo.sol b/contracts/governance/compatibility/IGovernorCompatibilityBravo.sol index d1ec0337d..159c55100 100644 --- a/contracts/governance/compatibility/IGovernorCompatibilityBravo.sol +++ b/contracts/governance/compatibility/IGovernorCompatibilityBravo.sol @@ -90,11 +90,6 @@ abstract contract IGovernorCompatibilityBravo is IGovernor { */ function execute(uint256 proposalId) public payable virtual; - /** - * @dev Cancels a proposal only if sender is the proposer, or proposer delegates dropped below proposal threshold. - */ - function cancel(uint256 proposalId) public virtual; - /** * @dev Part of the Governor Bravo's interface: _"Gets actions of a proposal"_. */ diff --git a/contracts/mocks/governance/GovernorCompatibilityBravoMock.sol b/contracts/mocks/governance/GovernorCompatibilityBravoMock.sol index 4356bce7f..2727794f6 100644 --- a/contracts/mocks/governance/GovernorCompatibilityBravoMock.sol +++ b/contracts/mocks/governance/GovernorCompatibilityBravoMock.sol @@ -66,6 +66,10 @@ abstract contract GovernorCompatibilityBravoMock is return super.execute(targets, values, calldatas, salt); } + function cancel(uint256 proposalId) public override(Governor, GovernorCompatibilityBravo, IGovernor) { + super.cancel(proposalId); + } + function _execute( uint256 proposalId, address[] memory targets, diff --git a/contracts/mocks/wizard/MyGovernor3.sol b/contracts/mocks/wizard/MyGovernor3.sol index 320342290..4192cae94 100644 --- a/contracts/mocks/wizard/MyGovernor3.sol +++ b/contracts/mocks/wizard/MyGovernor3.sol @@ -54,6 +54,10 @@ contract MyGovernor is return super.propose(targets, values, calldatas, description); } + function cancel(uint256 proposalId) public override(Governor, GovernorCompatibilityBravo, IGovernor) { + super.cancel(proposalId); + } + function _execute( uint256 proposalId, address[] memory targets, diff --git a/test/governance/Governor.test.js b/test/governance/Governor.test.js index cc3cc17ef..4c083ed92 100644 --- a/test/governance/Governor.test.js +++ b/test/governance/Governor.test.js @@ -382,55 +382,109 @@ contract('Governor', function (accounts) { }); describe('cancel', function () { - it('before proposal', async function () { - await expectRevert(this.helper.cancel(), 'Governor: unknown proposal id'); + describe('internal', function () { + it('before proposal', async function () { + await expectRevert(this.helper.cancel('internal'), 'Governor: unknown proposal id'); + }); + + it('after proposal', async function () { + await this.helper.propose(); + + await this.helper.cancel('internal'); + expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled); + + await this.helper.waitForSnapshot(); + await expectRevert( + this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }), + 'Governor: vote not currently active', + ); + }); + + it('after vote', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + + await this.helper.cancel('internal'); + expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled); + + await this.helper.waitForDeadline(); + await expectRevert(this.helper.execute(), 'Governor: proposal not successful'); + }); + + it('after deadline', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + + await this.helper.cancel('internal'); + expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled); + + await expectRevert(this.helper.execute(), 'Governor: proposal not successful'); + }); + + it('after execution', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await this.helper.execute(); + + await expectRevert(this.helper.cancel('internal'), 'Governor: proposal not active'); + }); }); - it('after proposal', async function () { - await this.helper.propose(); + describe('public', function () { + it('before proposal', async function () { + await expectRevert(this.helper.cancel('external'), 'Governor: unknown proposal id'); + }); - await this.helper.cancel(); - expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled); + it('after proposal', async function () { + await this.helper.propose(); - await this.helper.waitForSnapshot(); - await expectRevert( - this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }), - 'Governor: vote not currently active', - ); - }); + await this.helper.cancel('external'); + }); - it('after vote', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + it('after proposal - restricted to proposer', async function () { + await this.helper.propose(); - await this.helper.cancel(); - expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled); + await expectRevert(this.helper.cancel('external', { from: owner }), 'Governor: only proposer can cancel'); + }); - await this.helper.waitForDeadline(); - await expectRevert(this.helper.execute(), 'Governor: proposal not successful'); - }); + it('after vote started', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(1); // snapshot + 1 block - it('after deadline', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); + await expectRevert(this.helper.cancel('external'), 'Governor: too late to cancel'); + }); - await this.helper.cancel(); - expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled); + it('after vote', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await expectRevert(this.helper.execute(), 'Governor: proposal not successful'); - }); + await expectRevert(this.helper.cancel('external'), 'Governor: too late to cancel'); + }); - it('after execution', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - await this.helper.execute(); + it('after deadline', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); - await expectRevert(this.helper.cancel(), 'Governor: proposal not active'); + await expectRevert(this.helper.cancel('external'), 'Governor: too late to cancel'); + }); + + it('after execution', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await this.helper.execute(); + + await expectRevert(this.helper.cancel('external'), 'Governor: too late to cancel'); + }); }); }); diff --git a/test/governance/compatibility/GovernorCompatibilityBravo.test.js b/test/governance/compatibility/GovernorCompatibilityBravo.test.js index 231d57b27..3666c4548 100644 --- a/test/governance/compatibility/GovernorCompatibilityBravo.test.js +++ b/test/governance/compatibility/GovernorCompatibilityBravo.test.js @@ -226,18 +226,18 @@ contract('GovernorCompatibilityBravo', function (accounts) { describe('cancel', function () { it('proposer can cancel', async function () { await this.helper.propose({ from: proposer }); - await this.helper.cancel({ from: proposer }); + await this.helper.cancel('external', { from: proposer }); }); it('anyone can cancel if proposer drop below threshold', async function () { await this.helper.propose({ from: proposer }); await this.token.transfer(voter1, web3.utils.toWei('1'), { from: proposer }); - await this.helper.cancel(); + await this.helper.cancel('external'); }); it('cannot cancel is proposer is still above threshold', async function () { await this.helper.propose({ from: proposer }); - await expectRevert(this.helper.cancel(), 'GovernorBravo: proposer above threshold'); + await expectRevert(this.helper.cancel('external'), 'GovernorBravo: proposer above threshold'); }); }); }); diff --git a/test/governance/extensions/GovernorTimelockCompound.test.js b/test/governance/extensions/GovernorTimelockCompound.test.js index 334659e07..fb6803383 100644 --- a/test/governance/extensions/GovernorTimelockCompound.test.js +++ b/test/governance/extensions/GovernorTimelockCompound.test.js @@ -193,7 +193,7 @@ contract('GovernorTimelockCompound', function (accounts) { await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); await this.helper.waitForDeadline(); - expectEvent(await this.helper.cancel(), 'ProposalCanceled', { proposalId: this.proposal.id }); + expectEvent(await this.helper.cancel('internal'), 'ProposalCanceled', { proposalId: this.proposal.id }); expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled); await expectRevert(this.helper.queue(), 'Governor: proposal not successful'); @@ -206,7 +206,7 @@ contract('GovernorTimelockCompound', function (accounts) { await this.helper.waitForDeadline(); await this.helper.queue(); - expectEvent(await this.helper.cancel(), 'ProposalCanceled', { proposalId: this.proposal.id }); + expectEvent(await this.helper.cancel('internal'), 'ProposalCanceled', { proposalId: this.proposal.id }); expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled); await expectRevert(this.helper.execute(), 'Governor: proposal not successful'); diff --git a/test/governance/extensions/GovernorTimelockControl.test.js b/test/governance/extensions/GovernorTimelockControl.test.js index 2e8c75888..4f9b9df73 100644 --- a/test/governance/extensions/GovernorTimelockControl.test.js +++ b/test/governance/extensions/GovernorTimelockControl.test.js @@ -185,7 +185,7 @@ contract('GovernorTimelockControl', function (accounts) { await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); await this.helper.waitForDeadline(); - expectEvent(await this.helper.cancel(), 'ProposalCanceled', { proposalId: this.proposal.id }); + expectEvent(await this.helper.cancel('internal'), 'ProposalCanceled', { proposalId: this.proposal.id }); expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled); await expectRevert(this.helper.queue(), 'Governor: proposal not successful'); @@ -198,7 +198,7 @@ contract('GovernorTimelockControl', function (accounts) { await this.helper.waitForDeadline(); await this.helper.queue(); - expectEvent(await this.helper.cancel(), 'ProposalCanceled', { proposalId: this.proposal.id }); + expectEvent(await this.helper.cancel('internal'), 'ProposalCanceled', { proposalId: this.proposal.id }); expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled); await expectRevert(this.helper.execute(), 'Governor: proposal not successful'); diff --git a/test/helpers/governance.js b/test/helpers/governance.js index ff341aa12..f933f389d 100644 --- a/test/helpers/governance.js +++ b/test/helpers/governance.js @@ -62,14 +62,19 @@ class GovernorHelper { ); } - cancel(opts = null) { + cancel(visibility = 'external', opts = null) { const proposal = this.currentProposal; - return proposal.useCompatibilityInterface - ? this.governor.methods['cancel(uint256)'](...concatOpts([proposal.id], opts)) - : this.governor.methods['$_cancel(address[],uint256[],bytes[],bytes32)']( + switch (visibility) { + case 'external': + return this.governor.methods['cancel(uint256)'](...concatOpts([proposal.id], opts)); + case 'internal': + return this.governor.methods['$_cancel(address[],uint256[],bytes[],bytes32)']( ...concatOpts(proposal.shortProposal, opts), ); + default: + throw new Error(`unsuported visibility "${visibility}"`); + } } vote(vote = {}, opts = null) { From bc6de21fe229520b33d13a4d60bbeb1bc5f91bcd Mon Sep 17 00:00:00 2001 From: JulissaDantes Date: Fri, 27 Jan 2023 13:47:43 -0500 Subject: [PATCH 010/133] Create ProposalSalt event for TimelockController (#4001) Co-authored-by: Francisco --- .changeset/five-poets-mix.md | 5 ++++ contracts/governance/TimelockController.sol | 15 ++++++++++-- test/governance/TimelockController.test.js | 23 +++++++++++++++++++ .../GovernorTimelockControl.test.js | 3 +++ 4 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 .changeset/five-poets-mix.md diff --git a/.changeset/five-poets-mix.md b/.changeset/five-poets-mix.md new file mode 100644 index 000000000..f5050b246 --- /dev/null +++ b/.changeset/five-poets-mix.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': patch +--- + +`TimelockController`: Add the `CallSalt` event to emit on operation schedule. diff --git a/contracts/governance/TimelockController.sol b/contracts/governance/TimelockController.sol index dac55d858..615b4c0e3 100644 --- a/contracts/governance/TimelockController.sol +++ b/contracts/governance/TimelockController.sol @@ -51,6 +51,11 @@ contract TimelockController is AccessControl, IERC721Receiver, IERC1155Receiver */ event CallExecuted(bytes32 indexed id, uint256 indexed index, address target, uint256 value, bytes data); + /** + * @dev Emitted when new proposal is scheduled with non-zero salt. + */ + event CallSalt(bytes32 indexed id, bytes32 salt); + /** * @dev Emitted when operation `id` is cancelled. */ @@ -206,7 +211,7 @@ contract TimelockController is AccessControl, IERC721Receiver, IERC1155Receiver /** * @dev Schedule an operation containing a single transaction. * - * Emits a {CallScheduled} event. + * Emits events {CallScheduled} and {CallSalt}. * * Requirements: * @@ -223,12 +228,15 @@ contract TimelockController is AccessControl, IERC721Receiver, IERC1155Receiver bytes32 id = hashOperation(target, value, data, predecessor, salt); _schedule(id, delay); emit CallScheduled(id, 0, target, value, data, predecessor, delay); + if (salt != bytes32(0)) { + emit CallSalt(id, salt); + } } /** * @dev Schedule an operation containing a batch of transactions. * - * Emits one {CallScheduled} event per transaction in the batch. + * Emits a {CallSalt} event and one {CallScheduled} event per transaction in the batch. * * Requirements: * @@ -250,6 +258,9 @@ contract TimelockController is AccessControl, IERC721Receiver, IERC1155Receiver for (uint256 i = 0; i < targets.length; ++i) { emit CallScheduled(id, i, targets[i], values[i], payloads[i], predecessor, delay); } + if (salt != bytes32(0)) { + emit CallSalt(id, salt); + } } /** diff --git a/test/governance/TimelockController.test.js b/test/governance/TimelockController.test.js index 83352ef85..dde923564 100644 --- a/test/governance/TimelockController.test.js +++ b/test/governance/TimelockController.test.js @@ -158,6 +158,11 @@ contract('TimelockController', function (accounts) { delay: MINDELAY, }); + expectEvent(receipt, 'CallSalt', { + id: this.operation.id, + salt: this.operation.salt, + }); + const block = await web3.eth.getBlock(receipt.receipt.blockHash); expect(await this.mock.getTimestamp(this.operation.id)).to.be.bignumber.equal( @@ -219,6 +224,19 @@ contract('TimelockController', function (accounts) { 'TimelockController: insufficient delay', ); }); + + it('schedule operation with salt zero', async function () { + const { receipt } = await this.mock.schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + ZERO_BYTES32, + MINDELAY, + { from: proposer }, + ); + expectEvent.notEmitted(receipt, 'CallSalt'); + }); }); describe('execute', function () { @@ -364,6 +382,11 @@ contract('TimelockController', function (accounts) { predecessor: this.operation.predecessor, delay: MINDELAY, }); + + expectEvent(receipt, 'CallSalt', { + id: this.operation.id, + salt: this.operation.salt, + }); } const block = await web3.eth.getBlock(receipt.receipt.blockHash); diff --git a/test/governance/extensions/GovernorTimelockControl.test.js b/test/governance/extensions/GovernorTimelockControl.test.js index 4f9b9df73..34fdfe92f 100644 --- a/test/governance/extensions/GovernorTimelockControl.test.js +++ b/test/governance/extensions/GovernorTimelockControl.test.js @@ -106,6 +106,9 @@ contract('GovernorTimelockControl', function (accounts) { expectEvent(txQueue, 'ProposalQueued', { proposalId: this.proposal.id }); await expectEvent.inTransaction(txQueue.tx, this.timelock, 'CallScheduled', { id: this.proposal.timelockid }); + await expectEvent.inTransaction(txQueue.tx, this.timelock, 'CallSalt', { + id: this.proposal.timelockid, + }); expectEvent(txExecute, 'ProposalExecuted', { proposalId: this.proposal.id }); await expectEvent.inTransaction(txExecute.tx, this.timelock, 'CallExecuted', { id: this.proposal.timelockid }); From 1684c579223f02c9e78db3fbcf7a2106a6f7efe9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Garc=C3=ADa?= Date: Sat, 28 Jan 2023 17:21:07 -0600 Subject: [PATCH 011/133] Add `ERC*Pausable` warning for public pausing mechanism (#4007) Co-authored-by: Francisco --- .changeset/new-ways-own.md | 5 +++++ contracts/token/ERC1155/extensions/ERC1155Pausable.sol | 6 ++++++ contracts/token/ERC20/extensions/ERC20Pausable.sol | 6 ++++++ contracts/token/ERC721/extensions/ERC721Pausable.sol | 6 ++++++ 4 files changed, 23 insertions(+) create mode 100644 .changeset/new-ways-own.md diff --git a/.changeset/new-ways-own.md b/.changeset/new-ways-own.md new file mode 100644 index 000000000..f940bfeb7 --- /dev/null +++ b/.changeset/new-ways-own.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': patch +--- + +`ERC20Pausable`, `ERC721Pausable`, `ERC1155Pausable`: Add note regarding missing public pausing functionality diff --git a/contracts/token/ERC1155/extensions/ERC1155Pausable.sol b/contracts/token/ERC1155/extensions/ERC1155Pausable.sol index 64790e2aa..66ad55e7d 100644 --- a/contracts/token/ERC1155/extensions/ERC1155Pausable.sol +++ b/contracts/token/ERC1155/extensions/ERC1155Pausable.sol @@ -13,6 +13,12 @@ import "../../../security/Pausable.sol"; * period, or having an emergency switch for freezing all token transfers in the * event of a large bug. * + * IMPORTANT: This contract does not include public pause and unpause functions. In + * addition to inheriting this contract, you must define both functions, invoking the + * {Pausable-_pause} and {Pausable-_unpause} internal functions, with appropriate + * access control, e.g. using {AccessControl} or {Ownable}. Not doing so will + * make the contract unpausable. + * * _Available since v3.1._ */ abstract contract ERC1155Pausable is ERC1155, Pausable { diff --git a/contracts/token/ERC20/extensions/ERC20Pausable.sol b/contracts/token/ERC20/extensions/ERC20Pausable.sol index d0b224f4b..e011f08c0 100644 --- a/contracts/token/ERC20/extensions/ERC20Pausable.sol +++ b/contracts/token/ERC20/extensions/ERC20Pausable.sol @@ -12,6 +12,12 @@ import "../../../security/Pausable.sol"; * Useful for scenarios such as preventing trades until the end of an evaluation * period, or having an emergency switch for freezing all token transfers in the * event of a large bug. + * + * IMPORTANT: This contract does not include public pause and unpause functions. In + * addition to inheriting this contract, you must define both functions, invoking the + * {Pausable-_pause} and {Pausable-_unpause} internal functions, with appropriate + * access control, e.g. using {AccessControl} or {Ownable}. Not doing so will + * make the contract unpausable. */ abstract contract ERC20Pausable is ERC20, Pausable { /** diff --git a/contracts/token/ERC721/extensions/ERC721Pausable.sol b/contracts/token/ERC721/extensions/ERC721Pausable.sol index 4726540f4..cdd729b26 100644 --- a/contracts/token/ERC721/extensions/ERC721Pausable.sol +++ b/contracts/token/ERC721/extensions/ERC721Pausable.sol @@ -12,6 +12,12 @@ import "../../../security/Pausable.sol"; * Useful for scenarios such as preventing trades until the end of an evaluation * period, or having an emergency switch for freezing all token transfers in the * event of a large bug. + * + * IMPORTANT: This contract does not include public pause and unpause functions. In + * addition to inheriting this contract, you must define both functions, invoking the + * {Pausable-_pause} and {Pausable-_unpause} internal functions, with appropriate + * access control, e.g. using {AccessControl} or {Ownable}. Not doing so will + * make the contract unpausable. */ abstract contract ERC721Pausable is ERC721, Pausable { /** From 591c12d22de283a297e2b551175ccc914c938391 Mon Sep 17 00:00:00 2001 From: Francisco Date: Mon, 30 Jan 2023 21:00:56 -0300 Subject: [PATCH 012/133] Remove outdated note about virtual view functions (#4014) --- docs/modules/ROOT/pages/extending-contracts.adoc | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/modules/ROOT/pages/extending-contracts.adoc b/docs/modules/ROOT/pages/extending-contracts.adoc index 7330fc997..a440f4067 100644 --- a/docs/modules/ROOT/pages/extending-contracts.adoc +++ b/docs/modules/ROOT/pages/extending-contracts.adoc @@ -66,8 +66,6 @@ contract ModifiedAccessControl is AccessControl { The `super.revokeRole` statement at the end will invoke ``AccessControl``'s original version of `revokeRole`, the same code that would've run if there were no overrides in place. -NOTE: As of v3.0.0, `view` functions are not `virtual` in OpenZeppelin, and therefore cannot be overridden. We're considering https://github.com/OpenZeppelin/openzeppelin-contracts/issues/2154[lifting this restriction] in an upcoming release. Let us know if this is something you care about! - [[using-hooks]] == Using Hooks From 501a78e13426ec10249e44386239c74783478dd0 Mon Sep 17 00:00:00 2001 From: Mio Date: Tue, 31 Jan 2023 21:11:37 +0800 Subject: [PATCH 013/133] Fix typos (#4015) --- contracts/governance/IGovernor.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/governance/IGovernor.sol b/contracts/governance/IGovernor.sol index 18cf57fb1..60a4b5470 100644 --- a/contracts/governance/IGovernor.sol +++ b/contracts/governance/IGovernor.sol @@ -58,7 +58,7 @@ abstract contract IGovernor is IERC165 { * @dev Emitted when a vote is cast with params. * * Note: `support` values should be seen as buckets. Their interpretation depends on the voting module used. - * `params` are additional encoded parameters. Their intepepretation also depends on the voting module used. + * `params` are additional encoded parameters. Their interpepretation also depends on the voting module used. */ event VoteCastWithParams( address indexed voter, @@ -140,7 +140,7 @@ abstract contract IGovernor is IERC165 { /** * @notice module:user-config - * @dev Delay, in number of block, between the proposal is created and the vote starts. This can be increassed to + * @dev Delay, in number of block, between the proposal is created and the vote starts. This can be increased to * leave time for users to buy voting power, or delegate it, before the voting of a proposal starts. */ function votingDelay() public view virtual returns (uint256); From a70ee4e3bbee565e49217c9ec59de5354f8af9d8 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Tue, 31 Jan 2023 21:45:24 +0100 Subject: [PATCH 014/133] Check storage layout consistency in PRs (#3967) Co-authored-by: Francisco --- .github/actions/storage-layout/action.yml | 55 +++++++++ .github/workflows/checks.yml | 4 + package-lock.json | 144 ++++++++++++++++++++++ package.json | 1 + scripts/checks/compare-layout.js | 20 +++ scripts/checks/extract-layout.js | 40 ++++++ 6 files changed, 264 insertions(+) create mode 100644 .github/actions/storage-layout/action.yml create mode 100644 scripts/checks/compare-layout.js create mode 100644 scripts/checks/extract-layout.js diff --git a/.github/actions/storage-layout/action.yml b/.github/actions/storage-layout/action.yml new file mode 100644 index 000000000..e3e104a01 --- /dev/null +++ b/.github/actions/storage-layout/action.yml @@ -0,0 +1,55 @@ +name: Compare storage layouts +inputs: + token: + description: github token + required: true + buildinfo: + description: compilation artifacts + required: false + default: artifacts/build-info/*.json + layout: + description: extracted storage layout + required: false + default: HEAD.layout.json + out_layout: + description: storage layout to upload + required: false + default: ${{ github.ref_name }}.layout.json + ref_layout: + description: storage layout for the reference branch + required: false + default: ${{ github.base_ref }}.layout.json + +runs: + using: composite + steps: + - name: Extract layout + run: | + node scripts/checks/extract-layout.js ${{ inputs.buildinfo }} > ${{ inputs.layout }} + shell: bash + - name: Download reference + if: github.event_name == 'pull_request' + run: | + RUN_ID=`gh run list --repo ${{ github.repository }} --branch ${{ github.base_ref }} --workflow ${{ github.workflow }} --limit 100 --json 'conclusion,databaseId,event' --jq 'map(select(.conclusion=="success" and .event!="pull_request"))[0].databaseId'` + gh run download ${RUN_ID} --repo ${{ github.repository }} -n layout + env: + GITHUB_TOKEN: ${{ inputs.token }} + shell: bash + continue-on-error: true + id: reference + - name: Compare layouts + if: steps.reference.outcome == 'success' && github.event_name == 'pull_request' + run: | + node scripts/checks/compare-layout.js --head ${{ inputs.layout }} --ref ${{ inputs.ref_layout }} >> $GITHUB_STEP_SUMMARY + shell: bash + - name: Rename artifacts for upload + if: github.event_name != 'pull_request' + run: | + mv ${{ inputs.layout }} ${{ inputs.out_layout }} + shell: bash + - name: Save artifacts + if: github.event_name != 'pull_request' + uses: actions/upload-artifact@v3 + with: + name: layout + path: ${{ inputs.out_layout }} diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 17d9e3578..02664e85c 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -42,6 +42,10 @@ jobs: uses: ./.github/actions/gas-compare with: token: ${{ github.token }} + - name: Check storage layout + uses: ./.github/actions/storage-layout + with: + token: ${{ github.token }} foundry-tests: if: github.repository != 'OpenZeppelin/openzeppelin-contracts-upgradeable' diff --git a/package-lock.json b/package-lock.json index 51a71854c..51d350ac7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "@nomiclabs/hardhat-web3": "^2.0.0", "@openzeppelin/docs-utils": "^0.1.3", "@openzeppelin/test-helpers": "^0.5.13", + "@openzeppelin/upgrades-core": "^1.20.6", "chai": "^4.2.0", "eslint": "^8.30.0", "eslint-config-prettier": "^8.5.0", @@ -2405,6 +2406,58 @@ "semver": "bin/semver" } }, + "node_modules/@openzeppelin/upgrades-core": { + "version": "1.20.6", + "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades-core/-/upgrades-core-1.20.6.tgz", + "integrity": "sha512-KWdtlahm+iunlAlzLsdpBueanwEx0LLPfAkDL1p0C4SPjMiUqHHFlyGtmmWwdiqDpJ//605vfwkd5RqfnFrHSg==", + "dev": true, + "dependencies": { + "cbor": "^8.0.0", + "chalk": "^4.1.0", + "compare-versions": "^5.0.0", + "debug": "^4.1.1", + "ethereumjs-util": "^7.0.3", + "proper-lockfile": "^4.1.1", + "solidity-ast": "^0.4.15" + } + }, + "node_modules/@openzeppelin/upgrades-core/node_modules/cbor": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/cbor/-/cbor-8.1.0.tgz", + "integrity": "sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==", + "dev": true, + "dependencies": { + "nofilter": "^3.1.0" + }, + "engines": { + "node": ">=12.19" + } + }, + "node_modules/@openzeppelin/upgrades-core/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@openzeppelin/upgrades-core/node_modules/nofilter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz", + "integrity": "sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==", + "dev": true, + "engines": { + "node": ">=12.19" + } + }, "node_modules/@scure/base": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz", @@ -4571,6 +4624,12 @@ "integrity": "sha512-6CYPa+JP2ftfRU2qkDK+UTVeQYosOg/2GbcjIcKPHfinyOLPVGXu/ovN86RP49Re5ndJK1N0kuiidFFuepc4ZQ==", "dev": true }, + "node_modules/compare-versions": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-5.0.3.tgz", + "integrity": "sha512-4UZlZP8Z99MGEY+Ovg/uJxJuvoXuN4M6B3hKaiackiHrgzQFEe3diJi1mf1PNHbFujM7FvLrK2bpgIaImbtZ1A==", + "dev": true + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -11430,6 +11489,17 @@ "asap": "~2.0.6" } }, + "node_modules/proper-lockfile": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", + "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -12019,6 +12089,15 @@ "node": ">=4" } }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -17993,6 +18072,48 @@ } } }, + "@openzeppelin/upgrades-core": { + "version": "1.20.6", + "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades-core/-/upgrades-core-1.20.6.tgz", + "integrity": "sha512-KWdtlahm+iunlAlzLsdpBueanwEx0LLPfAkDL1p0C4SPjMiUqHHFlyGtmmWwdiqDpJ//605vfwkd5RqfnFrHSg==", + "dev": true, + "requires": { + "cbor": "^8.0.0", + "chalk": "^4.1.0", + "compare-versions": "^5.0.0", + "debug": "^4.1.1", + "ethereumjs-util": "^7.0.3", + "proper-lockfile": "^4.1.1", + "solidity-ast": "^0.4.15" + }, + "dependencies": { + "cbor": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/cbor/-/cbor-8.1.0.tgz", + "integrity": "sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==", + "dev": true, + "requires": { + "nofilter": "^3.1.0" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "nofilter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz", + "integrity": "sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==", + "dev": true + } + } + }, "@scure/base": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz", @@ -19767,6 +19888,12 @@ "integrity": "sha512-6CYPa+JP2ftfRU2qkDK+UTVeQYosOg/2GbcjIcKPHfinyOLPVGXu/ovN86RP49Re5ndJK1N0kuiidFFuepc4ZQ==", "dev": true }, + "compare-versions": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-5.0.3.tgz", + "integrity": "sha512-4UZlZP8Z99MGEY+Ovg/uJxJuvoXuN4M6B3hKaiackiHrgzQFEe3diJi1mf1PNHbFujM7FvLrK2bpgIaImbtZ1A==", + "dev": true + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -25154,6 +25281,17 @@ "asap": "~2.0.6" } }, + "proper-lockfile": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", + "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + } + }, "proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -25598,6 +25736,12 @@ "signal-exit": "^3.0.2" } }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true + }, "reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", diff --git a/package.json b/package.json index b4035b820..de2951bd1 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "@nomiclabs/hardhat-web3": "^2.0.0", "@openzeppelin/docs-utils": "^0.1.3", "@openzeppelin/test-helpers": "^0.5.13", + "@openzeppelin/upgrades-core": "^1.20.6", "chai": "^4.2.0", "eslint": "^8.30.0", "eslint-config-prettier": "^8.5.0", diff --git a/scripts/checks/compare-layout.js b/scripts/checks/compare-layout.js new file mode 100644 index 000000000..ff8cb712e --- /dev/null +++ b/scripts/checks/compare-layout.js @@ -0,0 +1,20 @@ +const fs = require('fs'); +const { getStorageUpgradeReport } = require('@openzeppelin/upgrades-core/dist/storage'); + +const { ref, head } = require('yargs').argv; + +const oldLayout = JSON.parse(fs.readFileSync(ref)); +const newLayout = JSON.parse(fs.readFileSync(head)); + +for (const name in oldLayout) { + if (name in newLayout) { + const report = getStorageUpgradeReport(oldLayout[name], newLayout[name], {}); + if (!report.ok) { + console.log(`ERROR: Storage incompatibility in ${name}`); + console.log(report.explain()); + process.exitCode = 1; + } + } else { + console.log(`WARNING: ${name} is missing from the current branch`); + } +} diff --git a/scripts/checks/extract-layout.js b/scripts/checks/extract-layout.js new file mode 100644 index 000000000..d0c9cf36b --- /dev/null +++ b/scripts/checks/extract-layout.js @@ -0,0 +1,40 @@ +const fs = require('fs'); +const { findAll } = require('solidity-ast/utils'); +const { astDereferencer } = require('@openzeppelin/upgrades-core/dist/ast-dereferencer'); +const { solcInputOutputDecoder } = require('@openzeppelin/upgrades-core/dist/src-decoder'); +const { extractStorageLayout } = require('@openzeppelin/upgrades-core/dist/storage/extract'); + +const { _ } = require('yargs').argv; + +const skipPath = ['contracts/mocks/', 'contracts-exposed/']; +const skipKind = ['interface', 'library']; + +function extractLayouts(path) { + const layout = {}; + const { input, output } = JSON.parse(fs.readFileSync(path)); + + const decoder = solcInputOutputDecoder(input, output); + const deref = astDereferencer(output); + + for (const src in output.contracts) { + if (skipPath.some(prefix => src.startsWith(prefix))) { + continue; + } + + for (const contractDef of findAll('ContractDefinition', output.sources[src].ast)) { + if (skipKind.includes(contractDef.contractKind)) { + continue; + } + + layout[contractDef.name] = extractStorageLayout( + contractDef, + decoder, + deref, + output.contracts[src][contractDef.name].storageLayout, + ); + } + } + return layout; +} + +console.log(JSON.stringify(Object.assign(..._.map(extractLayouts)))); From 91e8d0ba3c3beb8a1db31310d8599664e48639ef Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Wed, 1 Feb 2023 22:46:05 +0100 Subject: [PATCH 015/133] Add `string` and `bytes` support to the `StorageSlots` library (#4008) Co-authored-by: Francisco --- .changeset/modern-games-exist.md | 5 ++ contracts/mocks/StorageSlotMock.sol | 38 +++++++- contracts/utils/StorageSlot.sol | 52 ++++++++++- scripts/generate/run.js | 1 + scripts/generate/templates/StorageSlot.js | 87 +++++++++++++++++++ scripts/helpers.js | 5 ++ test/utils/StorageSlot.test.js | 100 ++++++++++++++++++++++ 7 files changed, 286 insertions(+), 2 deletions(-) create mode 100644 .changeset/modern-games-exist.md create mode 100644 scripts/generate/templates/StorageSlot.js diff --git a/.changeset/modern-games-exist.md b/.changeset/modern-games-exist.md new file mode 100644 index 000000000..bd89b4f16 --- /dev/null +++ b/.changeset/modern-games-exist.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': minor +--- + +`StorageSlot`: Add support for `string` and `bytes`. diff --git a/contracts/mocks/StorageSlotMock.sol b/contracts/mocks/StorageSlotMock.sol index 5d099fca8..1da577c19 100644 --- a/contracts/mocks/StorageSlotMock.sol +++ b/contracts/mocks/StorageSlotMock.sol @@ -5,7 +5,7 @@ pragma solidity ^0.8.0; import "../utils/StorageSlot.sol"; contract StorageSlotMock { - using StorageSlot for bytes32; + using StorageSlot for *; function setBoolean(bytes32 slot, bool value) public { slot.getBooleanSlot().value = value; @@ -38,4 +38,40 @@ contract StorageSlotMock { function getUint256(bytes32 slot) public view returns (uint256) { return slot.getUint256Slot().value; } + + mapping(uint256 => string) public stringMap; + + function setString(bytes32 slot, string calldata value) public { + slot.getStringSlot().value = value; + } + + function setStringStorage(uint256 key, string calldata value) public { + stringMap[key].getStringSlot().value = value; + } + + function getString(bytes32 slot) public view returns (string memory) { + return slot.getStringSlot().value; + } + + function getStringStorage(uint256 key) public view returns (string memory) { + return stringMap[key].getStringSlot().value; + } + + mapping(uint256 => bytes) public bytesMap; + + function setBytes(bytes32 slot, bytes calldata value) public { + slot.getBytesSlot().value = value; + } + + function setBytesStorage(uint256 key, bytes calldata value) public { + bytesMap[key].getBytesSlot().value = value; + } + + function getBytes(bytes32 slot) public view returns (bytes memory) { + return slot.getBytesSlot().value; + } + + function getBytesStorage(uint256 key) public view returns (bytes memory) { + return bytesMap[key].getBytesSlot().value; + } } diff --git a/contracts/utils/StorageSlot.sol b/contracts/utils/StorageSlot.sol index d23363bd6..44285c900 100644 --- a/contracts/utils/StorageSlot.sol +++ b/contracts/utils/StorageSlot.sol @@ -1,5 +1,6 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol) +// This file was procedurally generated from scripts/generate/templates/StorageSlot.js. pragma solidity ^0.8.0; @@ -27,7 +28,8 @@ pragma solidity ^0.8.0; * } * ``` * - * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._ + * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._ + * _Available since v4.9 for `string`, `bytes`._ */ library StorageSlot { struct AddressSlot { @@ -46,6 +48,14 @@ library StorageSlot { uint256 value; } + struct StringSlot { + string value; + } + + struct BytesSlot { + bytes value; + } + /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ @@ -85,4 +95,44 @@ library StorageSlot { r.slot := slot } } + + /** + * @dev Returns an `StringSlot` with member `value` located at `slot`. + */ + function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { + /// @solidity memory-safe-assembly + assembly { + r.slot := slot + } + } + + /** + * @dev Returns an `StringSlot` representation of the string storage pointer `store`. + */ + function getStringSlot(string storage store) internal pure returns (StringSlot storage r) { + /// @solidity memory-safe-assembly + assembly { + r.slot := store.slot + } + } + + /** + * @dev Returns an `BytesSlot` with member `value` located at `slot`. + */ + function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { + /// @solidity memory-safe-assembly + assembly { + r.slot := slot + } + } + + /** + * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`. + */ + function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) { + /// @solidity memory-safe-assembly + assembly { + r.slot := store.slot + } + } } diff --git a/scripts/generate/run.js b/scripts/generate/run.js index a34823223..e68681e9d 100755 --- a/scripts/generate/run.js +++ b/scripts/generate/run.js @@ -18,6 +18,7 @@ for (const [file, template] of Object.entries({ 'utils/structs/EnumerableSet.sol': './templates/EnumerableSet.js', 'utils/structs/EnumerableMap.sol': './templates/EnumerableMap.js', 'utils/Checkpoints.sol': './templates/Checkpoints.js', + 'utils/StorageSlot.sol': './templates/StorageSlot.js', })) { const script = path.relative(path.join(__dirname, '../..'), __filename); const input = path.join(path.dirname(script), template); diff --git a/scripts/generate/templates/StorageSlot.js b/scripts/generate/templates/StorageSlot.js new file mode 100644 index 000000000..69fa7ccc0 --- /dev/null +++ b/scripts/generate/templates/StorageSlot.js @@ -0,0 +1,87 @@ +const format = require('../format-lines'); +const { capitalize, unique } = require('../../helpers'); + +const TYPES = [ + { type: 'address', isValueType: true, version: '4.1' }, + { type: 'bool', isValueType: true, name: 'Boolean', version: '4.1' }, + { type: 'bytes32', isValueType: true, version: '4.1' }, + { type: 'uint256', isValueType: true, version: '4.1' }, + { type: 'string', isValueType: false, version: '4.9' }, + { type: 'bytes', isValueType: false, version: '4.9' }, +].map(type => Object.assign(type, { struct: (type.name ?? capitalize(type.type)) + 'Slot' })); + +const VERSIONS = unique(TYPES.map(t => t.version)).map( + version => + `_Available since v${version} for ${TYPES.filter(t => t.version == version) + .map(t => `\`${t.type}\``) + .join(', ')}._`, +); + +const header = `\ +pragma solidity ^0.8.0; + +/** + * @dev Library for reading and writing primitive types to specific storage slots. + * + * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. + * This library helps with reading and writing to such slots without the need for inline assembly. + * + * The functions in this library return Slot structs that contain a \`value\` member that can be used to read or write. + * + * Example usage to set ERC1967 implementation slot: + * \`\`\`solidity + * contract ERC1967 { + * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; + * + * function _getImplementation() internal view returns (address) { + * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; + * } + * + * function _setImplementation(address newImplementation) internal { + * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); + * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; + * } + * } + * \`\`\` + * +${VERSIONS.map(s => ` * ${s}`).join('\n')} + */ +`; + +const struct = type => `\ +struct ${type.struct} { + ${type.type} value; +} +`; + +const get = type => `\ +/** + * @dev Returns an \`${type.struct}\` with member \`value\` located at \`slot\`. + */ +function get${type.struct}(bytes32 slot) internal pure returns (${type.struct} storage r) { + /// @solidity memory-safe-assembly + assembly { + r.slot := slot + } +} +`; + +const getStorage = type => `\ +/** + * @dev Returns an \`${type.struct}\` representation of the ${type.type} storage pointer \`store\`. + */ +function get${type.struct}(${type.type} storage store) internal pure returns (${type.struct} storage r) { + /// @solidity memory-safe-assembly + assembly { + r.slot := store.slot + } +} +`; + +// GENERATE +module.exports = format( + header.trimEnd(), + 'library StorageSlot {', + [...TYPES.map(struct), ...TYPES.flatMap(type => [get(type), type.isValueType ? '' : getStorage(type)])], + '}', +); diff --git a/scripts/helpers.js b/scripts/helpers.js index 26d0a2baa..fb9aad4fc 100644 --- a/scripts/helpers.js +++ b/scripts/helpers.js @@ -24,9 +24,14 @@ function zip(...args) { .map((_, i) => args.map(arg => arg[i])); } +function capitalize(str) { + return str.charAt(0).toUpperCase() + str.slice(1); +} + module.exports = { chunk, range, unique, zip, + capitalize, }; diff --git a/test/utils/StorageSlot.test.js b/test/utils/StorageSlot.test.js index 9d428875f..846512ed2 100644 --- a/test/utils/StorageSlot.test.js +++ b/test/utils/StorageSlot.test.js @@ -107,4 +107,104 @@ contract('StorageSlot', function (accounts) { }); }); }); + + describe('string storage slot', function () { + beforeEach(async function () { + this.value = 'lorem ipsum'; + }); + + it('set', async function () { + await this.store.setString(slot, this.value); + }); + + describe('get', function () { + beforeEach(async function () { + await this.store.setString(slot, this.value); + }); + + it('from right slot', async function () { + expect(await this.store.getString(slot)).to.be.equal(this.value); + }); + + it('from other slot', async function () { + expect(await this.store.getString(otherSlot)).to.be.equal(''); + }); + }); + }); + + describe('string storage pointer', function () { + beforeEach(async function () { + this.value = 'lorem ipsum'; + }); + + it('set', async function () { + await this.store.setStringStorage(slot, this.value); + }); + + describe('get', function () { + beforeEach(async function () { + await this.store.setStringStorage(slot, this.value); + }); + + it('from right slot', async function () { + expect(await this.store.stringMap(slot)).to.be.equal(this.value); + expect(await this.store.getStringStorage(slot)).to.be.equal(this.value); + }); + + it('from other slot', async function () { + expect(await this.store.stringMap(otherSlot)).to.be.equal(''); + expect(await this.store.getStringStorage(otherSlot)).to.be.equal(''); + }); + }); + }); + + describe('bytes storage slot', function () { + beforeEach(async function () { + this.value = web3.utils.randomHex(128); + }); + + it('set', async function () { + await this.store.setBytes(slot, this.value); + }); + + describe('get', function () { + beforeEach(async function () { + await this.store.setBytes(slot, this.value); + }); + + it('from right slot', async function () { + expect(await this.store.getBytes(slot)).to.be.equal(this.value); + }); + + it('from other slot', async function () { + expect(await this.store.getBytes(otherSlot)).to.be.equal(null); + }); + }); + }); + + describe('bytes storage pointer', function () { + beforeEach(async function () { + this.value = web3.utils.randomHex(128); + }); + + it('set', async function () { + await this.store.setBytesStorage(slot, this.value); + }); + + describe('get', function () { + beforeEach(async function () { + await this.store.setBytesStorage(slot, this.value); + }); + + it('from right slot', async function () { + expect(await this.store.bytesMap(slot)).to.be.equal(this.value); + expect(await this.store.getBytesStorage(slot)).to.be.equal(this.value); + }); + + it('from other slot', async function () { + expect(await this.store.bytesMap(otherSlot)).to.be.equal(null); + expect(await this.store.getBytesStorage(otherSlot)).to.be.equal(null); + }); + }); + }); }); From 740ce2d440766e5013640f0e47640fae57f5d1d5 Mon Sep 17 00:00:00 2001 From: Francisco Date: Thu, 2 Feb 2023 21:08:41 -0300 Subject: [PATCH 016/133] Update renovate.json --- renovate.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/renovate.json b/renovate.json index 875bf6ec4..c0b97d8d7 100644 --- a/renovate.json +++ b/renovate.json @@ -1,4 +1,4 @@ { "extends": ["github>OpenZeppelin/configs"], - "labels": ["ignore-changelog"] + "labels": ["ignore-changeset"] } From 132e5aa97bd8f453f9556534a50b51b4b3bb9c2f Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Fri, 3 Feb 2023 19:57:47 +0100 Subject: [PATCH 017/133] Add IERC5313.sol (#4013) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ernesto García --- .changeset/happy-socks-travel.md | 5 +++++ contracts/interfaces/IERC5313.sol | 17 +++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 .changeset/happy-socks-travel.md create mode 100644 contracts/interfaces/IERC5313.sol diff --git a/.changeset/happy-socks-travel.md b/.changeset/happy-socks-travel.md new file mode 100644 index 000000000..b29d6bacd --- /dev/null +++ b/.changeset/happy-socks-travel.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': minor +--- + +`IERC5313`: Add an interface for EIP-5313 that is now final. diff --git a/contracts/interfaces/IERC5313.sol b/contracts/interfaces/IERC5313.sol new file mode 100644 index 000000000..2c9a47da9 --- /dev/null +++ b/contracts/interfaces/IERC5313.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev Interface for the Light Contract Ownership Standard. + * + * A standardized minimal interface required to identify an account that controls a contract + * + * _Available since v4.9._ + */ +interface IERC5313 { + /** + * @dev Gets the address of the owner. + */ + function owner() external view returns (address); +} From d13ec90f3719b6a1182b96455aea1ba21699f197 Mon Sep 17 00:00:00 2001 From: Yamen Merhi Date: Fri, 3 Feb 2023 21:15:41 +0200 Subject: [PATCH 018/133] Add warning for `supportsERC165InterfaceUnchecked` edge case (#4017) --- contracts/utils/introspection/ERC165Checker.sol | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contracts/utils/introspection/ERC165Checker.sol b/contracts/utils/introspection/ERC165Checker.sol index 40ffd68f7..db6939d83 100644 --- a/contracts/utils/introspection/ERC165Checker.sol +++ b/contracts/utils/introspection/ERC165Checker.sol @@ -101,6 +101,10 @@ library ERC165Checker { * @dev Assumes that account contains a contract that supports ERC165, otherwise * the behavior of this method is undefined. This precondition can be checked * with {supportsERC165}. + * + * Some precompiled contracts will falsely indicate support for a given interface, so caution + * should be exercised when using this function. + * * Interface identification is specified in ERC-165. */ function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) internal view returns (bool) { From 3b591a48acaab78008ed39d60fbcf429a83155ca Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Fri, 3 Feb 2023 21:15:59 -0300 Subject: [PATCH 019/133] Add storageLayout to outputSelection --- hardhat.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/hardhat.config.js b/hardhat.config.js index 74f40c4d1..32f721b65 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -72,6 +72,7 @@ module.exports = { runs: 200, }, viaIR: withOptimizations && argv.ir, + outputSelection: { '*': { '*': ['storageLayout'] } }, }, }, warnings: { From 260e082ed10e86e5870c4e5859750a8271eeb2b9 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Mon, 6 Feb 2023 09:59:25 +0100 Subject: [PATCH 020/133] Add a library for handling short strings in a gas efficient way (#4023) Co-authored-by: Francisco --- .changeset/violet-frogs-hide.md | 5 ++ contracts/utils/README.adoc | 2 + contracts/utils/ShortStrings.sol | 94 ++++++++++++++++++++++++++++++++ package-lock.json | 14 ++--- package.json | 2 +- test/utils/ShortStrings.test.js | 44 +++++++++++++++ 6 files changed, 153 insertions(+), 8 deletions(-) create mode 100644 .changeset/violet-frogs-hide.md create mode 100644 contracts/utils/ShortStrings.sol create mode 100644 test/utils/ShortStrings.test.js diff --git a/.changeset/violet-frogs-hide.md b/.changeset/violet-frogs-hide.md new file mode 100644 index 000000000..21d2bf984 --- /dev/null +++ b/.changeset/violet-frogs-hide.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': minor +--- + +`ShortStrings`: Added a library for handling short strings in a gas efficient way, with fallback to storage for longer strings. diff --git a/contracts/utils/README.adoc b/contracts/utils/README.adoc index 7fef825a6..5e8af93e3 100644 --- a/contracts/utils/README.adoc +++ b/contracts/utils/README.adoc @@ -106,6 +106,8 @@ Note that, in all cases, accounts simply _declare_ their interfaces, but they ar {{Strings}} +{{ShortStrings}} + {{StorageSlot}} {{Multicall}} diff --git a/contracts/utils/ShortStrings.sol b/contracts/utils/ShortStrings.sol new file mode 100644 index 000000000..9f253df82 --- /dev/null +++ b/contracts/utils/ShortStrings.sol @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.8; + +import "./StorageSlot.sol"; + +type ShortString is bytes32; + +/** + * @dev This library provides functions to convert short memory strings + * into a `ShortString` type that can be used as an immutable variable. + * Strings of arbitrary length can be optimized if they are short enough by + * the addition of a storage variable used as fallback. + * + * Usage example: + * + * ```solidity + * contract Named { + * using ShortStrings for *; + * + * ShortString private immutable _name; + * string private _nameFallback; + * + * constructor(string memory contractName) { + * _name = contractName.toShortStringWithFallback(_nameFallback); + * } + * + * function name() external view returns (string memory) { + * return _name.toStringWithFallback(_nameFallback); + * } + * } + * ``` + */ +library ShortStrings { + error StringTooLong(string str); + + /** + * @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. + */ + function toShortString(string memory str) internal pure returns (ShortString) { + bytes memory bstr = bytes(str); + if (bstr.length > 31) { + revert StringTooLong(str); + } + return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length)); + } + + /** + * @dev Decode a `ShortString` back to a "normal" string. + */ + function toString(ShortString sstr) internal pure returns (string memory) { + uint256 len = length(sstr); + // using `new string(len)` would work locally but is not memory safe. + string memory str = new string(32); + /// @solidity memory-safe-assembly + assembly { + mstore(str, len) + mstore(add(str, 0x20), sstr) + } + return str; + } + + /** + * @dev Return the length of a `ShortString`. + */ + function length(ShortString sstr) internal pure returns (uint256) { + return uint256(ShortString.unwrap(sstr)) & 0xFF; + } + + /** + * @dev Encode a string into a `ShortString`, or write it to storage if it is too long. + */ + function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) { + if (bytes(value).length < 32) { + return toShortString(value); + } else { + StorageSlot.getStringSlot(store).value = value; + return ShortString.wrap(0); + } + } + + /** + * @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}. + */ + function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) { + if (length(value) > 0) { + return toString(value); + } else { + return store; + } + } +} diff --git a/package-lock.json b/package-lock.json index 51d350ac7..a663055fd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,7 +31,7 @@ "glob": "^8.0.3", "graphlib": "^2.1.8", "hardhat": "^2.9.1", - "hardhat-exposed": "^0.3.0", + "hardhat-exposed": "^0.3.1", "hardhat-gas-reporter": "^1.0.4", "hardhat-ignore-warnings": "^0.2.0", "keccak256": "^1.0.2", @@ -7923,9 +7923,9 @@ } }, "node_modules/hardhat-exposed": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/hardhat-exposed/-/hardhat-exposed-0.3.0.tgz", - "integrity": "sha512-1p2Aou7QW3VVI0iJhh3q9hgPyF66zggeW7v/PrcipniQqaXK+KxJnnJvzGsLvXYzB8lVp23GIK7MXoTjjyXkHQ==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/hardhat-exposed/-/hardhat-exposed-0.3.1.tgz", + "integrity": "sha512-qyHXdS3NmzrtXF+XL547BMsTAK+IEMW9OOYMH4d362DlPn4L2B2KXKG6OpuJczxYjgMFJ0LunLxNgu6jtRvjRg==", "dev": true, "dependencies": { "micromatch": "^4.0.4", @@ -22753,9 +22753,9 @@ } }, "hardhat-exposed": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/hardhat-exposed/-/hardhat-exposed-0.3.0.tgz", - "integrity": "sha512-1p2Aou7QW3VVI0iJhh3q9hgPyF66zggeW7v/PrcipniQqaXK+KxJnnJvzGsLvXYzB8lVp23GIK7MXoTjjyXkHQ==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/hardhat-exposed/-/hardhat-exposed-0.3.1.tgz", + "integrity": "sha512-qyHXdS3NmzrtXF+XL547BMsTAK+IEMW9OOYMH4d362DlPn4L2B2KXKG6OpuJczxYjgMFJ0LunLxNgu6jtRvjRg==", "dev": true, "requires": { "micromatch": "^4.0.4", diff --git a/package.json b/package.json index de2951bd1..66d44888a 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "glob": "^8.0.3", "graphlib": "^2.1.8", "hardhat": "^2.9.1", - "hardhat-exposed": "^0.3.0", + "hardhat-exposed": "^0.3.1", "hardhat-gas-reporter": "^1.0.4", "hardhat-ignore-warnings": "^0.2.0", "keccak256": "^1.0.2", diff --git a/test/utils/ShortStrings.test.js b/test/utils/ShortStrings.test.js new file mode 100644 index 000000000..f41084a7e --- /dev/null +++ b/test/utils/ShortStrings.test.js @@ -0,0 +1,44 @@ +const { expect } = require('chai'); +const { expectRevertCustomError } = require('../helpers/customError'); + +const ShortStrings = artifacts.require('$ShortStrings'); + +function decode(sstr) { + const length = parseInt(sstr.slice(64), 16); + return web3.utils.toUtf8(sstr).slice(0, length); +} + +contract('ShortStrings', function () { + before(async function () { + this.mock = await ShortStrings.new(); + }); + + for (const str of [0, 1, 16, 31, 32, 64, 1024].map(length => 'a'.repeat(length))) { + describe(`with string length ${str.length}`, function () { + it('encode / decode', async function () { + if (str.length < 32) { + const encoded = await this.mock.$toShortString(str); + expect(decode(encoded)).to.be.equal(str); + + const length = await this.mock.$length(encoded); + expect(length.toNumber()).to.be.equal(str.length); + + const decoded = await this.mock.$toString(encoded); + expect(decoded).to.be.equal(str); + } else { + await expectRevertCustomError(this.mock.$toShortString(str), `StringTooLong("${str}")`); + } + }); + + it('set / get with fallback', async function () { + const { logs } = await this.mock.$toShortStringWithFallback(str, 0); + const { ret0 } = logs.find(({ event }) => event == 'return$toShortStringWithFallback').args; + + expect(await this.mock.$toString(ret0)).to.be.equal(str.length < 32 ? str : ''); + + const recovered = await this.mock.$toStringWithFallback(ret0, 0); + expect(recovered).to.be.equal(str); + }); + }); + } +}); From 1575cc6908f0f38bfb36d459c4ce7295f0f89c49 Mon Sep 17 00:00:00 2001 From: Francisco Date: Mon, 6 Feb 2023 12:20:12 -0300 Subject: [PATCH 021/133] Update Tally screenshots (#4030) --- docs/modules/ROOT/images/tally-admin.png | Bin 22024 -> 0 bytes docs/modules/ROOT/images/tally-exec.png | Bin 0 -> 231859 bytes docs/modules/ROOT/images/tally-vote.png | Bin 33437 -> 40507 bytes docs/modules/ROOT/pages/governance.adoc | 4 ++-- 4 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 docs/modules/ROOT/images/tally-admin.png create mode 100644 docs/modules/ROOT/images/tally-exec.png diff --git a/docs/modules/ROOT/images/tally-admin.png b/docs/modules/ROOT/images/tally-admin.png deleted file mode 100644 index 8265259302418995cbc0ee77128e6dde20d1dfe0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22024 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
>t>*+2Sz_Kd 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∈YQ8Q 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 VZVAzj{5LR4@tvC7A6e6o{|B=b*sA~l literal 0 HcmV?d00001 diff --git a/docs/modules/ROOT/images/tally-vote.png b/docs/modules/ROOT/images/tally-vote.png index 76e9b3a981eb5bf394ccfc2814ee28d3c22e2d51..7d270fce091298627d9c181c315415c7710de784 100644 GIT binary patch literal 40507 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 H55fNfLFfw_ diff --git a/docs/modules/ROOT/pages/governance.adoc b/docs/modules/ROOT/pages/governance.adoc index d59e3ce9f..358a63e90 100644 --- a/docs/modules/ROOT/pages/governance.adoc +++ b/docs/modules/ROOT/pages/governance.adoc @@ -284,9 +284,9 @@ image::tally-vote.png[Voting in Tally] === Execute the Proposal -Once the voting period is over, if quorum was reached (enough voting power participated) and the majority voted in favor, the proposal is considered successful and can proceed to be executed. This can also be done in Tally in the "Administration Panel" section of a project. +Once the voting period is over, if quorum was reached (enough voting power participated) and the majority voted in favor, the proposal is considered successful and can proceed to be executed. Once a proposal passes, it can be queued and executed from the same place you voted. -image::tally-admin.png[Administration Panel in Tally] +image::tally-exec.png[Administration Panel in Tally] We will see now how to do this manually using Ethers.js. From 95027565c41aafd80512b63a4195194d78ae687d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Garc=C3=ADa?= Date: Tue, 7 Feb 2023 19:15:24 -0600 Subject: [PATCH 022/133] Improve `release-cycle.yml` error reporting (#4034) --- scripts/release/workflow/start.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/release/workflow/start.sh b/scripts/release/workflow/start.sh index 6e5d78b82..7683ec5bc 100644 --- a/scripts/release/workflow/start.sh +++ b/scripts/release/workflow/start.sh @@ -29,4 +29,7 @@ git add . git commit -m "Start release candidate" # Push branch -git push origin "$RELEASE_BRANCH" +if ! git push origin "$RELEASE_BRANCH"; then + echo "::error file=scripts/release/start.sh::Can't push $RELEASE_BRANCH. Did you forget to run this workflow from $RELEASE_BRANCH?" + exit 1 +fi From 4d3e423443d0d0f80861235e5b58866572640114 Mon Sep 17 00:00:00 2001 From: Kimani Kelly Date: Tue, 7 Feb 2023 20:16:36 -0500 Subject: [PATCH 023/133] Make ERC20Wrapper.underlying variable private (#4029) Co-authored-by: Kimani Kelly Co-authored-by: Hadrien Croubois --- .changeset/proud-comics-deliver.md | 5 +++++ .../token/ERC20/extensions/ERC20Wrapper.sol | 19 +++++++++++++------ 2 files changed, 18 insertions(+), 6 deletions(-) create mode 100644 .changeset/proud-comics-deliver.md diff --git a/.changeset/proud-comics-deliver.md b/.changeset/proud-comics-deliver.md new file mode 100644 index 000000000..e9c1015f8 --- /dev/null +++ b/.changeset/proud-comics-deliver.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': minor +--- + +`ERC20Wrapper`: Make the `underlying` variable private and add a public accessor. diff --git a/contracts/token/ERC20/extensions/ERC20Wrapper.sol b/contracts/token/ERC20/extensions/ERC20Wrapper.sol index 8b153ffca..ce515693e 100644 --- a/contracts/token/ERC20/extensions/ERC20Wrapper.sol +++ b/contracts/token/ERC20/extensions/ERC20Wrapper.sol @@ -16,28 +16,35 @@ import "../utils/SafeERC20.sol"; * _Available since v4.2._ */ abstract contract ERC20Wrapper is ERC20 { - IERC20 public immutable underlying; + IERC20 private immutable _underlying; constructor(IERC20 underlyingToken) { - underlying = underlyingToken; + _underlying = underlyingToken; } /** * @dev See {ERC20-decimals}. */ function decimals() public view virtual override returns (uint8) { - try IERC20Metadata(address(underlying)).decimals() returns (uint8 value) { + try IERC20Metadata(address(_underlying)).decimals() returns (uint8 value) { return value; } catch { return super.decimals(); } } + /** + * @dev Returns the address of the underlying ERC-20 token that is being wrapped. + */ + function underlying() public view returns (IERC20) { + return _underlying; + } + /** * @dev Allow a user to deposit underlying tokens and mint the corresponding number of wrapped tokens. */ function depositFor(address account, uint256 amount) public virtual returns (bool) { - SafeERC20.safeTransferFrom(underlying, _msgSender(), address(this), amount); + SafeERC20.safeTransferFrom(_underlying, _msgSender(), address(this), amount); _mint(account, amount); return true; } @@ -47,7 +54,7 @@ abstract contract ERC20Wrapper is ERC20 { */ function withdrawTo(address account, uint256 amount) public virtual returns (bool) { _burn(_msgSender(), amount); - SafeERC20.safeTransfer(underlying, account, amount); + SafeERC20.safeTransfer(_underlying, account, amount); return true; } @@ -56,7 +63,7 @@ abstract contract ERC20Wrapper is ERC20 { * function that can be exposed with access control if desired. */ function _recover(address account) internal virtual returns (uint256) { - uint256 value = underlying.balanceOf(address(this)) - totalSupply(); + uint256 value = _underlying.balanceOf(address(this)) - totalSupply(); _mint(account, value); return value; } From 8177c4620e049b2749c2069651d7d5b4691e23d2 Mon Sep 17 00:00:00 2001 From: TheGreatHB <74754077+TheGreatHB@users.noreply.github.com> Date: Wed, 8 Feb 2023 10:18:33 +0900 Subject: [PATCH 024/133] Improve gas efficiency in ECDSA (#3853) Signed-off-by: Pascal Marco Caversaccio Co-authored-by: Hadrien Croubois Co-authored-by: Pascal Marco Caversaccio --- .changeset/thin-dragons-report.md | 5 +++++ contracts/utils/cryptography/ECDSA.sol | 20 ++++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 .changeset/thin-dragons-report.md diff --git a/.changeset/thin-dragons-report.md b/.changeset/thin-dragons-report.md new file mode 100644 index 000000000..b73730f7f --- /dev/null +++ b/.changeset/thin-dragons-report.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': minor +--- + +`ECDSA`: optimize bytes32 computation by using assembly instead of `abi.encodePacked`. diff --git a/contracts/utils/cryptography/ECDSA.sol b/contracts/utils/cryptography/ECDSA.sol index 3f996520e..a499b546b 100644 --- a/contracts/utils/cryptography/ECDSA.sol +++ b/contracts/utils/cryptography/ECDSA.sol @@ -162,10 +162,15 @@ library ECDSA { * * See {recover}. */ - function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { + function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) { // 32 is the length in bytes of hash, // enforced by the type signature above - return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, "\x19Ethereum Signed Message:\n32") + mstore(0x1c, hash) + message := keccak256(0x00, 0x3c) + } } /** @@ -189,7 +194,14 @@ library ECDSA { * * See {recover}. */ - function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) { - return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); + function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) { + /// @solidity memory-safe-assembly + assembly { + let ptr := mload(0x40) + mstore(ptr, "\x19\x01") + mstore(add(ptr, 0x02), domainSeparator) + mstore(add(ptr, 0x22), structHash) + data := keccak256(ptr, 0x42) + } } } From d625cb45ea1aa83ee51c75a9e6cf824c38ee6426 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Wed, 8 Feb 2023 15:53:57 +0100 Subject: [PATCH 025/133] Include EIP-5267 discovery in EIP-712 (#3969) Co-authored-by: Francisco Co-authored-by: Francisco --- .changeset/short-roses-judge.md | 5 + CHANGELOG.md | 5 + contracts/interfaces/IERC5267.sol | 27 +++++ contracts/utils/cryptography/EIP712.sol | 95 ++++++++++----- test/governance/Governor.test.js | 35 +++--- .../extensions/GovernorWithParams.test.js | 39 +++--- test/governance/utils/Votes.behavior.js | 113 ++++++++---------- test/helpers/eip712.js | 39 ++++-- test/helpers/governance.js | 4 +- test/metatx/ERC2771Context.test.js | 15 +-- test/metatx/MinimalForwarder.test.js | 17 +-- .../token/ERC20/extensions/ERC20Votes.test.js | 104 +++++++--------- .../ERC20/extensions/ERC20VotesComp.test.js | 104 +++++++--------- .../extensions/draft-ERC20Permit.test.js | 44 +++---- test/token/ERC20/utils/SafeERC20.test.js | 14 +-- test/utils/cryptography/EIP712.test.js | 23 ++-- 16 files changed, 358 insertions(+), 325 deletions(-) create mode 100644 .changeset/short-roses-judge.md create mode 100644 contracts/interfaces/IERC5267.sol diff --git a/.changeset/short-roses-judge.md b/.changeset/short-roses-judge.md new file mode 100644 index 000000000..002aebb11 --- /dev/null +++ b/.changeset/short-roses-judge.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': minor +--- + +`EIP712`: add EIP-5267 support for better domain discovery. diff --git a/CHANGELOG.md b/CHANGELOG.md index e60161db0..ccd279d53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +### Breaking changes + +- `EIP712`: Addition of ERC5267 support requires support for user defined value types, which was released in Solidity version 0.8.8. This requires a pragma change from `^0.8.0` to `^0.8.8`. +- `EIP712`: Optimization of the cache for the upgradeable version affects the way `name` and `version` are set. This is no longer done through an initializer, and is instead part of the implementation's constructor. As a consequence, all proxies using the same implementation will necessarily share the same `name` and `version`. Additionally, an implementation upgrade risks changing the EIP712 domain unless the same `name` and `version` are used when deploying the new implementation contract. + ### Deprecations - `ERC20Permit`: Added the file `IERC20Permit.sol` and `ERC20Permit.sol` and deprecated `draft-IERC20Permit.sol` and `draft-ERC20Permit.sol` since [EIP-2612](https://eips.ethereum.org/EIPS/eip-2612) is no longer a Draft. Developers are encouraged to update their imports. ([#3793](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3793)) diff --git a/contracts/interfaces/IERC5267.sol b/contracts/interfaces/IERC5267.sol new file mode 100644 index 000000000..3adc4a703 --- /dev/null +++ b/contracts/interfaces/IERC5267.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +interface IERC5267 { + /** + * @dev MAY be emitted to signal that the domain could have changed. + */ + event EIP712DomainChanged(); + + /** + * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712 + * signature. + */ + function eip712Domain() + external + view + returns ( + bytes1 fields, + string memory name, + string memory version, + uint256 chainId, + address verifyingContract, + bytes32 salt, + uint256[] memory extensions + ); +} diff --git a/contracts/utils/cryptography/EIP712.sol b/contracts/utils/cryptography/EIP712.sol index eb211a7e2..d0e52c396 100644 --- a/contracts/utils/cryptography/EIP712.sol +++ b/contracts/utils/cryptography/EIP712.sol @@ -1,9 +1,11 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/EIP712.sol) -pragma solidity ^0.8.0; +pragma solidity ^0.8.8; import "./ECDSA.sol"; +import "../ShortStrings.sol"; +import "../../interfaces/IERC5267.sol"; /** * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. @@ -22,19 +24,34 @@ import "./ECDSA.sol"; * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. * + * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain + * separator of the implementation contract. This will cause the `_domainSeparatorV4` function to always rebuild the + * separator from the immutable values, which is cheaper than accessing a cached version in cold storage. + * * _Available since v3.4._ + * + * @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment */ -abstract contract EIP712 { +abstract contract EIP712 is IERC5267 { + using ShortStrings for *; + + bytes32 private constant _TYPE_HASH = + keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); + /* solhint-disable var-name-mixedcase */ // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to // invalidate the cached domain separator if the chain id changes. - bytes32 private immutable _CACHED_DOMAIN_SEPARATOR; - uint256 private immutable _CACHED_CHAIN_ID; - address private immutable _CACHED_THIS; + bytes32 private immutable _cachedDomainSeparator; + uint256 private immutable _cachedChainId; + address private immutable _cachedThis; - bytes32 private immutable _HASHED_NAME; - bytes32 private immutable _HASHED_VERSION; - bytes32 private immutable _TYPE_HASH; + ShortString private immutable _name; + ShortString private immutable _version; + string private _nameFallback; + string private _versionFallback; + + bytes32 private immutable _hashedName; + bytes32 private immutable _hashedVersion; /* solhint-enable var-name-mixedcase */ @@ -51,36 +68,29 @@ abstract contract EIP712 { * contract upgrade]. */ constructor(string memory name, string memory version) { - bytes32 hashedName = keccak256(bytes(name)); - bytes32 hashedVersion = keccak256(bytes(version)); - bytes32 typeHash = keccak256( - "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" - ); - _HASHED_NAME = hashedName; - _HASHED_VERSION = hashedVersion; - _CACHED_CHAIN_ID = block.chainid; - _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion); - _CACHED_THIS = address(this); - _TYPE_HASH = typeHash; + _name = name.toShortStringWithFallback(_nameFallback); + _version = version.toShortStringWithFallback(_versionFallback); + _hashedName = keccak256(bytes(name)); + _hashedVersion = keccak256(bytes(version)); + + _cachedChainId = block.chainid; + _cachedDomainSeparator = _buildDomainSeparator(); + _cachedThis = address(this); } /** * @dev Returns the domain separator for the current chain. */ function _domainSeparatorV4() internal view returns (bytes32) { - if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) { - return _CACHED_DOMAIN_SEPARATOR; + if (address(this) == _cachedThis && block.chainid == _cachedChainId) { + return _cachedDomainSeparator; } else { - return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION); + return _buildDomainSeparator(); } } - function _buildDomainSeparator( - bytes32 typeHash, - bytes32 nameHash, - bytes32 versionHash - ) private view returns (bytes32) { - return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this))); + function _buildDomainSeparator() private view returns (bytes32) { + return keccak256(abi.encode(_TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this))); } /** @@ -101,4 +111,33 @@ abstract contract EIP712 { function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash); } + + /** + * @dev See {EIP-5267}. + */ + function eip712Domain() + public + view + virtual + override + returns ( + bytes1 fields, + string memory name, + string memory version, + uint256 chainId, + address verifyingContract, + bytes32 salt, + uint256[] memory extensions + ) + { + return ( + hex"0f", // 01111 + _name.toStringWithFallback(_nameFallback), + _version.toStringWithFallback(_versionFallback), + block.chainid, + address(this), + bytes32(0), + new uint256[](0) + ); + } } diff --git a/test/governance/Governor.test.js b/test/governance/Governor.test.js index 4c083ed92..201895934 100644 --- a/test/governance/Governor.test.js +++ b/test/governance/Governor.test.js @@ -4,7 +4,7 @@ const ethSigUtil = require('eth-sig-util'); const Wallet = require('ethereumjs-wallet').default; const { fromRpcSig } = require('ethereumjs-util'); const Enums = require('../helpers/enums'); -const { EIP712Domain } = require('../helpers/eip712'); +const { getDomain, domainType } = require('../helpers/eip712'); const { GovernorHelper } = require('../helpers/governance'); const { shouldSupportInterfaces } = require('../utils/introspection/SupportsInterface.behavior'); @@ -20,7 +20,6 @@ contract('Governor', function (accounts) { const empty = web3.utils.toChecksumAddress(web3.utils.randomHex(20)); const name = 'OZ-Governor'; - const version = '1'; const tokenName = 'MockToken'; const tokenSymbol = 'MTKN'; const tokenSupply = web3.utils.toWei('100'); @@ -148,24 +147,22 @@ contract('Governor', function (accounts) { const voterBySig = Wallet.generate(); const voterBySigAddress = web3.utils.toChecksumAddress(voterBySig.getAddressString()); - const signature = async message => { - return fromRpcSig( - ethSigUtil.signTypedMessage(voterBySig.getPrivateKey(), { - data: { - types: { - EIP712Domain, - Ballot: [ - { name: 'proposalId', type: 'uint256' }, - { name: 'support', type: 'uint8' }, - ], - }, - domain: { name, version, chainId: this.chainId, verifyingContract: this.mock.address }, - primaryType: 'Ballot', - message, + const signature = (contract, message) => + getDomain(contract) + .then(domain => ({ + primaryType: 'Ballot', + types: { + EIP712Domain: domainType(domain), + Ballot: [ + { name: 'proposalId', type: 'uint256' }, + { name: 'support', type: 'uint8' }, + ], }, - }), - ); - }; + domain, + message, + })) + .then(data => ethSigUtil.signTypedMessage(voterBySig.getPrivateKey(), { data })) + .then(fromRpcSig); await this.token.delegate(voterBySigAddress, { from: voter1 }); diff --git a/test/governance/extensions/GovernorWithParams.test.js b/test/governance/extensions/GovernorWithParams.test.js index 26e948544..86ebacc08 100644 --- a/test/governance/extensions/GovernorWithParams.test.js +++ b/test/governance/extensions/GovernorWithParams.test.js @@ -4,7 +4,7 @@ const ethSigUtil = require('eth-sig-util'); const Wallet = require('ethereumjs-wallet').default; const { fromRpcSig } = require('ethereumjs-util'); const Enums = require('../../helpers/enums'); -const { EIP712Domain } = require('../../helpers/eip712'); +const { getDomain, domainType } = require('../../helpers/eip712'); const { GovernorHelper } = require('../../helpers/governance'); const Token = artifacts.require('$ERC20VotesComp'); @@ -22,7 +22,6 @@ contract('GovernorWithParams', function (accounts) { const [owner, proposer, voter1, voter2, voter3, voter4] = accounts; const name = 'OZ-Governor'; - const version = '1'; const tokenName = 'MockToken'; const tokenSymbol = 'MTKN'; const tokenSupply = web3.utils.toWei('100'); @@ -116,26 +115,24 @@ contract('GovernorWithParams', function (accounts) { const voterBySig = Wallet.generate(); const voterBySigAddress = web3.utils.toChecksumAddress(voterBySig.getAddressString()); - const signature = async message => { - return fromRpcSig( - ethSigUtil.signTypedMessage(voterBySig.getPrivateKey(), { - data: { - types: { - EIP712Domain, - ExtendedBallot: [ - { name: 'proposalId', type: 'uint256' }, - { name: 'support', type: 'uint8' }, - { name: 'reason', type: 'string' }, - { name: 'params', type: 'bytes' }, - ], - }, - domain: { name, version, chainId: this.chainId, verifyingContract: this.mock.address }, - primaryType: 'ExtendedBallot', - message, + const signature = (contract, message) => + getDomain(contract) + .then(domain => ({ + primaryType: 'ExtendedBallot', + types: { + EIP712Domain: domainType(domain), + ExtendedBallot: [ + { name: 'proposalId', type: 'uint256' }, + { name: 'support', type: 'uint8' }, + { name: 'reason', type: 'string' }, + { name: 'params', type: 'bytes' }, + ], }, - }), - ); - }; + domain, + message, + })) + .then(data => ethSigUtil.signTypedMessage(voterBySig.getPrivateKey(), { data })) + .then(fromRpcSig); await this.token.delegate(voterBySigAddress, { from: voter2 }); diff --git a/test/governance/utils/Votes.behavior.js b/test/governance/utils/Votes.behavior.js index 5062a9c97..8fe34dc47 100644 --- a/test/governance/utils/Votes.behavior.js +++ b/test/governance/utils/Votes.behavior.js @@ -6,7 +6,7 @@ const { fromRpcSig } = require('ethereumjs-util'); const ethSigUtil = require('eth-sig-util'); const Wallet = require('ethereumjs-wallet').default; -const { EIP712Domain, domainSeparator } = require('../../helpers/eip712'); +const { getDomain, domainType, domainSeparator } = require('../../helpers/eip712'); const Delegation = [ { name: 'delegatee', type: 'address' }, @@ -14,8 +14,6 @@ const Delegation = [ { name: 'expiry', type: 'uint256' }, ]; -const version = '1'; - function shouldBehaveLikeVotes() { describe('run votes workflow', function () { it('initial nonce is 0', async function () { @@ -23,14 +21,7 @@ function shouldBehaveLikeVotes() { }); it('domain separator', async function () { - expect(await this.votes.DOMAIN_SEPARATOR()).to.equal( - await domainSeparator({ - name: this.name, - version, - chainId: this.chainId, - verifyingContract: this.votes.address, - }), - ); + expect(await this.votes.DOMAIN_SEPARATOR()).to.equal(domainSeparator(await getDomain(this.votes))); }); describe('delegation with signature', function () { @@ -38,29 +29,29 @@ function shouldBehaveLikeVotes() { const delegatorAddress = web3.utils.toChecksumAddress(delegator.getAddressString()); const nonce = 0; - const buildData = (chainId, verifyingContract, name, message) => ({ - data: { + const buildAndSignData = async (contract, message, pk) => { + const data = await getDomain(contract).then(domain => ({ primaryType: 'Delegation', - types: { EIP712Domain, Delegation }, - domain: { name, version, chainId, verifyingContract }, + types: { EIP712Domain: domainType(domain), Delegation }, + domain, message, - }, - }); + })); + return fromRpcSig(ethSigUtil.signTypedMessage(pk, { data })); + }; beforeEach(async function () { await this.votes.$_mint(delegatorAddress, this.NFT0); }); it('accept signed delegation', async function () { - const { v, r, s } = fromRpcSig( - ethSigUtil.signTypedMessage( - delegator.getPrivateKey(), - buildData(this.chainId, this.votes.address, this.name, { - delegatee: delegatorAddress, - nonce, - expiry: MAX_UINT256, - }), - ), + const { v, r, s } = await buildAndSignData( + this.votes, + { + delegatee: delegatorAddress, + nonce, + expiry: MAX_UINT256, + }, + delegator.getPrivateKey(), ); expect(await this.votes.delegates(delegatorAddress)).to.be.equal(ZERO_ADDRESS); @@ -86,15 +77,14 @@ function shouldBehaveLikeVotes() { }); it('rejects reused signature', async function () { - const { v, r, s } = fromRpcSig( - ethSigUtil.signTypedMessage( - delegator.getPrivateKey(), - buildData(this.chainId, this.votes.address, this.name, { - delegatee: delegatorAddress, - nonce, - expiry: MAX_UINT256, - }), - ), + const { v, r, s } = await buildAndSignData( + this.votes, + { + delegatee: delegatorAddress, + nonce, + expiry: MAX_UINT256, + }, + delegator.getPrivateKey(), ); await this.votes.delegateBySig(delegatorAddress, nonce, MAX_UINT256, v, r, s); @@ -106,15 +96,14 @@ function shouldBehaveLikeVotes() { }); it('rejects bad delegatee', async function () { - const { v, r, s } = fromRpcSig( - ethSigUtil.signTypedMessage( - delegator.getPrivateKey(), - buildData(this.chainId, this.votes.address, this.name, { - delegatee: delegatorAddress, - nonce, - expiry: MAX_UINT256, - }), - ), + const { v, r, s } = await buildAndSignData( + this.votes, + { + delegatee: delegatorAddress, + nonce, + expiry: MAX_UINT256, + }, + delegator.getPrivateKey(), ); const receipt = await this.votes.delegateBySig(this.account1Delegatee, nonce, MAX_UINT256, v, r, s); @@ -125,16 +114,16 @@ function shouldBehaveLikeVotes() { }); it('rejects bad nonce', async function () { - const { v, r, s } = fromRpcSig( - ethSigUtil.signTypedMessage( - delegator.getPrivateKey(), - buildData(this.chainId, this.votes.address, this.name, { - delegatee: delegatorAddress, - nonce, - expiry: MAX_UINT256, - }), - ), + const { v, r, s } = await buildAndSignData( + this.votes, + { + delegatee: delegatorAddress, + nonce, + expiry: MAX_UINT256, + }, + delegator.getPrivateKey(), ); + await expectRevert( this.votes.delegateBySig(delegatorAddress, nonce + 1, MAX_UINT256, v, r, s), 'Votes: invalid nonce', @@ -143,15 +132,15 @@ function shouldBehaveLikeVotes() { it('rejects expired permit', async function () { const expiry = (await time.latest()) - time.duration.weeks(1); - const { v, r, s } = fromRpcSig( - ethSigUtil.signTypedMessage( - delegator.getPrivateKey(), - buildData(this.chainId, this.votes.address, this.name, { - delegatee: delegatorAddress, - nonce, - expiry, - }), - ), + + const { v, r, s } = await buildAndSignData( + this.votes, + { + delegatee: delegatorAddress, + nonce, + expiry, + }, + delegator.getPrivateKey(), ); await expectRevert( diff --git a/test/helpers/eip712.js b/test/helpers/eip712.js index 9851df662..b12a6233e 100644 --- a/test/helpers/eip712.js +++ b/test/helpers/eip712.js @@ -6,6 +6,7 @@ const EIP712Domain = [ { name: 'version', type: 'string' }, { name: 'chainId', type: 'uint256' }, { name: 'verifyingContract', type: 'address' }, + { name: 'salt', type: 'bytes32' }, ]; const Permit = [ @@ -24,25 +25,43 @@ function hexStringToBuffer(hexstr) { return Buffer.from(hexstr.replace(/^0x/, ''), 'hex'); } -async function domainSeparator({ name, version, chainId, verifyingContract }) { +async function getDomain(contract) { + const { fields, name, version, chainId, verifyingContract, salt, extensions } = await contract.eip712Domain(); + + if (extensions.length > 0) { + throw Error('Extensions not implemented'); + } + + const domain = { name, version, chainId, verifyingContract, salt }; + for (const [i, { name }] of EIP712Domain.entries()) { + if (!(fields & (1 << i))) { + delete domain[name]; + } + } + + return domain; +} + +function domainType(domain) { + return EIP712Domain.filter(({ name }) => domain[name] !== undefined); +} + +function domainSeparator(domain) { return bufferToHexString( - ethSigUtil.TypedDataUtils.hashStruct( - 'EIP712Domain', - { name, version, chainId, verifyingContract }, - { EIP712Domain }, - ), + ethSigUtil.TypedDataUtils.hashStruct('EIP712Domain', domain, { EIP712Domain: domainType(domain) }), ); } -async function hashTypedData(domain, structHash) { - return domainSeparator(domain).then(separator => - bufferToHexString(keccak256(Buffer.concat(['0x1901', separator, structHash].map(str => hexStringToBuffer(str))))), +function hashTypedData(domain, structHash) { + return bufferToHexString( + keccak256(Buffer.concat(['0x1901', domainSeparator(domain), structHash].map(str => hexStringToBuffer(str)))), ); } module.exports = { - EIP712Domain, Permit, + getDomain, + domainType, domainSeparator, hashTypedData, }; diff --git a/test/helpers/governance.js b/test/helpers/governance.js index f933f389d..b945a16e0 100644 --- a/test/helpers/governance.js +++ b/test/helpers/governance.js @@ -84,7 +84,7 @@ class GovernorHelper { ? // if signature, and either params or reason → vote.params || vote.reason ? vote - .signature({ + .signature(this.governor, { proposalId: proposal.id, support: vote.support, reason: vote.reason || '', @@ -96,7 +96,7 @@ class GovernorHelper { ), ) : vote - .signature({ + .signature(this.governor, { proposalId: proposal.id, support: vote.support, }) diff --git a/test/metatx/ERC2771Context.test.js b/test/metatx/ERC2771Context.test.js index 788777726..6c298d3d9 100644 --- a/test/metatx/ERC2771Context.test.js +++ b/test/metatx/ERC2771Context.test.js @@ -1,6 +1,6 @@ const ethSigUtil = require('eth-sig-util'); const Wallet = require('ethereumjs-wallet').default; -const { EIP712Domain } = require('../helpers/eip712'); +const { getDomain, domainType } = require('../helpers/eip712'); const { expectEvent } = require('@openzeppelin/test-helpers'); const { expect } = require('chai'); @@ -10,24 +10,15 @@ const MinimalForwarder = artifacts.require('MinimalForwarder'); const ContextMockCaller = artifacts.require('ContextMockCaller'); const { shouldBehaveLikeRegularContext } = require('../utils/Context.behavior'); -const { getChainId } = require('../helpers/chainid'); - -const name = 'MinimalForwarder'; -const version = '0.0.1'; contract('ERC2771Context', function (accounts) { beforeEach(async function () { this.forwarder = await MinimalForwarder.new(); this.recipient = await ERC2771ContextMock.new(this.forwarder.address); - this.domain = { - name, - version, - chainId: await getChainId(), - verifyingContract: this.forwarder.address, - }; + this.domain = await getDomain(this.forwarder); this.types = { - EIP712Domain, + EIP712Domain: domainType(this.domain), ForwardRequest: [ { name: 'from', type: 'address' }, { name: 'to', type: 'address' }, diff --git a/test/metatx/MinimalForwarder.test.js b/test/metatx/MinimalForwarder.test.js index 24de1719d..4884cc760 100644 --- a/test/metatx/MinimalForwarder.test.js +++ b/test/metatx/MinimalForwarder.test.js @@ -1,29 +1,20 @@ const ethSigUtil = require('eth-sig-util'); const Wallet = require('ethereumjs-wallet').default; -const { EIP712Domain } = require('../helpers/eip712'); +const { getDomain, domainType } = require('../helpers/eip712'); const { expectRevert, constants } = require('@openzeppelin/test-helpers'); const { expect } = require('chai'); -const { getChainId } = require('../helpers/chainid'); - const MinimalForwarder = artifacts.require('MinimalForwarder'); const CallReceiverMock = artifacts.require('CallReceiverMock'); -const name = 'MinimalForwarder'; -const version = '0.0.1'; - contract('MinimalForwarder', function (accounts) { beforeEach(async function () { this.forwarder = await MinimalForwarder.new(); - this.domain = { - name, - version, - chainId: await getChainId(), - verifyingContract: this.forwarder.address, - }; + + this.domain = await getDomain(this.forwarder); this.types = { - EIP712Domain, + EIP712Domain: domainType(this.domain), ForwardRequest: [ { name: 'from', type: 'address' }, { name: 'to', type: 'address' }, diff --git a/test/token/ERC20/extensions/ERC20Votes.test.js b/test/token/ERC20/extensions/ERC20Votes.test.js index a340e71a7..9759c1162 100644 --- a/test/token/ERC20/extensions/ERC20Votes.test.js +++ b/test/token/ERC20/extensions/ERC20Votes.test.js @@ -11,7 +11,7 @@ const Wallet = require('ethereumjs-wallet').default; const ERC20Votes = artifacts.require('$ERC20Votes'); const { batchInBlock } = require('../../../helpers/txpool'); -const { EIP712Domain, domainSeparator } = require('../../../helpers/eip712'); +const { getDomain, domainType, domainSeparator } = require('../../../helpers/eip712'); const { getChainId } = require('../../../helpers/chainid'); const Delegation = [ @@ -38,9 +38,7 @@ contract('ERC20Votes', function (accounts) { }); it('domain separator', async function () { - expect(await this.token.DOMAIN_SEPARATOR()).to.equal( - await domainSeparator({ name, version, chainId: this.chainId, verifyingContract: this.token.address }), - ); + expect(await this.token.DOMAIN_SEPARATOR()).to.equal(await getDomain(this.token).then(domainSeparator)); }); it('minting restriction', async function () { @@ -107,30 +105,26 @@ contract('ERC20Votes', function (accounts) { const delegatorAddress = web3.utils.toChecksumAddress(delegator.getAddressString()); const nonce = 0; - const buildData = (chainId, verifyingContract, message) => ({ - data: { + const buildData = (contract, message) => + getDomain(contract).then(domain => ({ primaryType: 'Delegation', - types: { EIP712Domain, Delegation }, - domain: { name, version, chainId, verifyingContract }, + types: { EIP712Domain: domainType(domain), Delegation }, + domain, message, - }, - }); + })); beforeEach(async function () { await this.token.$_mint(delegatorAddress, supply); }); it('accept signed delegation', async function () { - const { v, r, s } = fromRpcSig( - ethSigUtil.signTypedMessage( - delegator.getPrivateKey(), - buildData(this.chainId, this.token.address, { - delegatee: delegatorAddress, - nonce, - expiry: MAX_UINT256, - }), - ), - ); + const { v, r, s } = await buildData(this.token, { + delegatee: delegatorAddress, + nonce, + expiry: MAX_UINT256, + }) + .then(data => ethSigUtil.signTypedMessage(delegator.getPrivateKey(), { data })) + .then(fromRpcSig); expect(await this.token.delegates(delegatorAddress)).to.be.equal(ZERO_ADDRESS); @@ -155,16 +149,13 @@ contract('ERC20Votes', function (accounts) { }); it('rejects reused signature', async function () { - const { v, r, s } = fromRpcSig( - ethSigUtil.signTypedMessage( - delegator.getPrivateKey(), - buildData(this.chainId, this.token.address, { - delegatee: delegatorAddress, - nonce, - expiry: MAX_UINT256, - }), - ), - ); + const { v, r, s } = await buildData(this.token, { + delegatee: delegatorAddress, + nonce, + expiry: MAX_UINT256, + }) + .then(data => ethSigUtil.signTypedMessage(delegator.getPrivateKey(), { data })) + .then(fromRpcSig); await this.token.delegateBySig(delegatorAddress, nonce, MAX_UINT256, v, r, s); @@ -175,16 +166,13 @@ contract('ERC20Votes', function (accounts) { }); it('rejects bad delegatee', async function () { - const { v, r, s } = fromRpcSig( - ethSigUtil.signTypedMessage( - delegator.getPrivateKey(), - buildData(this.chainId, this.token.address, { - delegatee: delegatorAddress, - nonce, - expiry: MAX_UINT256, - }), - ), - ); + const { v, r, s } = await buildData(this.token, { + delegatee: delegatorAddress, + nonce, + expiry: MAX_UINT256, + }) + .then(data => ethSigUtil.signTypedMessage(delegator.getPrivateKey(), { data })) + .then(fromRpcSig); const receipt = await this.token.delegateBySig(holderDelegatee, nonce, MAX_UINT256, v, r, s); const { args } = receipt.logs.find(({ event }) => event == 'DelegateChanged'); @@ -194,16 +182,14 @@ contract('ERC20Votes', function (accounts) { }); it('rejects bad nonce', async function () { - const { v, r, s } = fromRpcSig( - ethSigUtil.signTypedMessage( - delegator.getPrivateKey(), - buildData(this.chainId, this.token.address, { - delegatee: delegatorAddress, - nonce, - expiry: MAX_UINT256, - }), - ), - ); + const { v, r, s } = await buildData(this.token, { + delegatee: delegatorAddress, + nonce, + expiry: MAX_UINT256, + }) + .then(data => ethSigUtil.signTypedMessage(delegator.getPrivateKey(), { data })) + .then(fromRpcSig); + await expectRevert( this.token.delegateBySig(delegatorAddress, nonce + 1, MAX_UINT256, v, r, s), 'ERC20Votes: invalid nonce', @@ -212,16 +198,14 @@ contract('ERC20Votes', function (accounts) { it('rejects expired permit', async function () { const expiry = (await time.latest()) - time.duration.weeks(1); - const { v, r, s } = fromRpcSig( - ethSigUtil.signTypedMessage( - delegator.getPrivateKey(), - buildData(this.chainId, this.token.address, { - delegatee: delegatorAddress, - nonce, - expiry, - }), - ), - ); + + const { v, r, s } = await buildData(this.token, { + delegatee: delegatorAddress, + nonce, + expiry, + }) + .then(data => ethSigUtil.signTypedMessage(delegator.getPrivateKey(), { data })) + .then(fromRpcSig); await expectRevert( this.token.delegateBySig(delegatorAddress, nonce, expiry, v, r, s), diff --git a/test/token/ERC20/extensions/ERC20VotesComp.test.js b/test/token/ERC20/extensions/ERC20VotesComp.test.js index 6a7c00013..660ed2124 100644 --- a/test/token/ERC20/extensions/ERC20VotesComp.test.js +++ b/test/token/ERC20/extensions/ERC20VotesComp.test.js @@ -11,7 +11,7 @@ const Wallet = require('ethereumjs-wallet').default; const ERC20VotesComp = artifacts.require('$ERC20VotesComp'); const { batchInBlock } = require('../../../helpers/txpool'); -const { EIP712Domain, domainSeparator } = require('../../../helpers/eip712'); +const { getDomain, domainType, domainSeparator } = require('../../../helpers/eip712'); const { getChainId } = require('../../../helpers/chainid'); const Delegation = [ @@ -38,9 +38,7 @@ contract('ERC20VotesComp', function (accounts) { }); it('domain separator', async function () { - expect(await this.token.DOMAIN_SEPARATOR()).to.equal( - await domainSeparator({ name, version, chainId: this.chainId, verifyingContract: this.token.address }), - ); + expect(await this.token.DOMAIN_SEPARATOR()).to.equal(await getDomain(this.token).then(domainSeparator)); }); it('minting restriction', async function () { @@ -94,30 +92,26 @@ contract('ERC20VotesComp', function (accounts) { const delegatorAddress = web3.utils.toChecksumAddress(delegator.getAddressString()); const nonce = 0; - const buildData = (chainId, verifyingContract, message) => ({ - data: { + const buildData = (contract, message) => + getDomain(contract).then(domain => ({ primaryType: 'Delegation', - types: { EIP712Domain, Delegation }, - domain: { name, version, chainId, verifyingContract }, + types: { EIP712Domain: domainType(domain), Delegation }, + domain, message, - }, - }); + })); beforeEach(async function () { await this.token.$_mint(delegatorAddress, supply); }); it('accept signed delegation', async function () { - const { v, r, s } = fromRpcSig( - ethSigUtil.signTypedMessage( - delegator.getPrivateKey(), - buildData(this.chainId, this.token.address, { - delegatee: delegatorAddress, - nonce, - expiry: MAX_UINT256, - }), - ), - ); + const { v, r, s } = await buildData(this.token, { + delegatee: delegatorAddress, + nonce, + expiry: MAX_UINT256, + }) + .then(data => ethSigUtil.signTypedMessage(delegator.getPrivateKey(), { data })) + .then(fromRpcSig); expect(await this.token.delegates(delegatorAddress)).to.be.equal(ZERO_ADDRESS); @@ -142,16 +136,13 @@ contract('ERC20VotesComp', function (accounts) { }); it('rejects reused signature', async function () { - const { v, r, s } = fromRpcSig( - ethSigUtil.signTypedMessage( - delegator.getPrivateKey(), - buildData(this.chainId, this.token.address, { - delegatee: delegatorAddress, - nonce, - expiry: MAX_UINT256, - }), - ), - ); + const { v, r, s } = await buildData(this.token, { + delegatee: delegatorAddress, + nonce, + expiry: MAX_UINT256, + }) + .then(data => ethSigUtil.signTypedMessage(delegator.getPrivateKey(), { data })) + .then(fromRpcSig); await this.token.delegateBySig(delegatorAddress, nonce, MAX_UINT256, v, r, s); @@ -162,16 +153,13 @@ contract('ERC20VotesComp', function (accounts) { }); it('rejects bad delegatee', async function () { - const { v, r, s } = fromRpcSig( - ethSigUtil.signTypedMessage( - delegator.getPrivateKey(), - buildData(this.chainId, this.token.address, { - delegatee: delegatorAddress, - nonce, - expiry: MAX_UINT256, - }), - ), - ); + const { v, r, s } = await buildData(this.token, { + delegatee: delegatorAddress, + nonce, + expiry: MAX_UINT256, + }) + .then(data => ethSigUtil.signTypedMessage(delegator.getPrivateKey(), { data })) + .then(fromRpcSig); const receipt = await this.token.delegateBySig(holderDelegatee, nonce, MAX_UINT256, v, r, s); const { args } = receipt.logs.find(({ event }) => event == 'DelegateChanged'); @@ -181,16 +169,14 @@ contract('ERC20VotesComp', function (accounts) { }); it('rejects bad nonce', async function () { - const { v, r, s } = fromRpcSig( - ethSigUtil.signTypedMessage( - delegator.getPrivateKey(), - buildData(this.chainId, this.token.address, { - delegatee: delegatorAddress, - nonce, - expiry: MAX_UINT256, - }), - ), - ); + const { v, r, s } = await buildData(this.token, { + delegatee: delegatorAddress, + nonce, + expiry: MAX_UINT256, + }) + .then(data => ethSigUtil.signTypedMessage(delegator.getPrivateKey(), { data })) + .then(fromRpcSig); + await expectRevert( this.token.delegateBySig(delegatorAddress, nonce + 1, MAX_UINT256, v, r, s), 'ERC20Votes: invalid nonce', @@ -199,16 +185,14 @@ contract('ERC20VotesComp', function (accounts) { it('rejects expired permit', async function () { const expiry = (await time.latest()) - time.duration.weeks(1); - const { v, r, s } = fromRpcSig( - ethSigUtil.signTypedMessage( - delegator.getPrivateKey(), - buildData(this.chainId, this.token.address, { - delegatee: delegatorAddress, - nonce, - expiry, - }), - ), - ); + + const { v, r, s } = await buildData(this.token, { + delegatee: delegatorAddress, + nonce, + expiry, + }) + .then(data => ethSigUtil.signTypedMessage(delegator.getPrivateKey(), { data })) + .then(fromRpcSig); await expectRevert( this.token.delegateBySig(delegatorAddress, nonce, expiry, v, r, s), diff --git a/test/token/ERC20/extensions/draft-ERC20Permit.test.js b/test/token/ERC20/extensions/draft-ERC20Permit.test.js index eb6737826..33c43c479 100644 --- a/test/token/ERC20/extensions/draft-ERC20Permit.test.js +++ b/test/token/ERC20/extensions/draft-ERC20Permit.test.js @@ -10,7 +10,7 @@ const Wallet = require('ethereumjs-wallet').default; const ERC20Permit = artifacts.require('$ERC20Permit'); -const { EIP712Domain, Permit, domainSeparator } = require('../../../helpers/eip712'); +const { Permit, getDomain, domainType, domainSeparator } = require('../../../helpers/eip712'); const { getChainId } = require('../../../helpers/chainid'); contract('ERC20Permit', function (accounts) { @@ -34,9 +34,7 @@ contract('ERC20Permit', function (accounts) { }); it('domain separator', async function () { - expect(await this.token.DOMAIN_SEPARATOR()).to.equal( - await domainSeparator({ name, version, chainId: this.chainId, verifyingContract: this.token.address }), - ); + expect(await this.token.DOMAIN_SEPARATOR()).to.equal(await getDomain(this.token).then(domainSeparator)); }); describe('permit', function () { @@ -47,17 +45,18 @@ contract('ERC20Permit', function (accounts) { const nonce = 0; const maxDeadline = MAX_UINT256; - const buildData = (chainId, verifyingContract, deadline = maxDeadline) => ({ - primaryType: 'Permit', - types: { EIP712Domain, Permit }, - domain: { name, version, chainId, verifyingContract }, - message: { owner, spender, value, nonce, deadline }, - }); + const buildData = (contract, deadline = maxDeadline) => + getDomain(contract).then(domain => ({ + primaryType: 'Permit', + types: { EIP712Domain: domainType(domain), Permit }, + domain, + message: { owner, spender, value, nonce, deadline }, + })); it('accepts owner signature', async function () { - const data = buildData(this.chainId, this.token.address); - const signature = ethSigUtil.signTypedMessage(wallet.getPrivateKey(), { data }); - const { v, r, s } = fromRpcSig(signature); + const { v, r, s } = await buildData(this.token) + .then(data => ethSigUtil.signTypedMessage(wallet.getPrivateKey(), { data })) + .then(fromRpcSig); await this.token.permit(owner, spender, value, maxDeadline, v, r, s); @@ -66,9 +65,9 @@ contract('ERC20Permit', function (accounts) { }); it('rejects reused signature', async function () { - const data = buildData(this.chainId, this.token.address); - const signature = ethSigUtil.signTypedMessage(wallet.getPrivateKey(), { data }); - const { v, r, s } = fromRpcSig(signature); + const { v, r, s } = await buildData(this.token) + .then(data => ethSigUtil.signTypedMessage(wallet.getPrivateKey(), { data })) + .then(fromRpcSig); await this.token.permit(owner, spender, value, maxDeadline, v, r, s); @@ -80,9 +79,10 @@ contract('ERC20Permit', function (accounts) { it('rejects other signature', async function () { const otherWallet = Wallet.generate(); - const data = buildData(this.chainId, this.token.address); - const signature = ethSigUtil.signTypedMessage(otherWallet.getPrivateKey(), { data }); - const { v, r, s } = fromRpcSig(signature); + + const { v, r, s } = await buildData(this.token) + .then(data => ethSigUtil.signTypedMessage(otherWallet.getPrivateKey(), { data })) + .then(fromRpcSig); await expectRevert( this.token.permit(owner, spender, value, maxDeadline, v, r, s), @@ -93,9 +93,9 @@ contract('ERC20Permit', function (accounts) { it('rejects expired permit', async function () { const deadline = (await time.latest()) - time.duration.weeks(1); - const data = buildData(this.chainId, this.token.address, deadline); - const signature = ethSigUtil.signTypedMessage(wallet.getPrivateKey(), { data }); - const { v, r, s } = fromRpcSig(signature); + const { v, r, s } = await buildData(this.token, deadline) + .then(data => ethSigUtil.signTypedMessage(wallet.getPrivateKey(), { data })) + .then(fromRpcSig); await expectRevert(this.token.permit(owner, spender, value, deadline, v, r, s), 'ERC20Permit: expired deadline'); }); diff --git a/test/token/ERC20/utils/SafeERC20.test.js b/test/token/ERC20/utils/SafeERC20.test.js index 878989cb1..a6b10fae3 100644 --- a/test/token/ERC20/utils/SafeERC20.test.js +++ b/test/token/ERC20/utils/SafeERC20.test.js @@ -6,8 +6,7 @@ const ERC20ReturnTrueMock = artifacts.require('ERC20ReturnTrueMock'); const ERC20NoReturnMock = artifacts.require('ERC20NoReturnMock'); const ERC20PermitNoRevertMock = artifacts.require('ERC20PermitNoRevertMock'); -const { EIP712Domain, Permit } = require('../../../helpers/eip712'); -const { getChainId } = require('../../../helpers/chainid'); +const { getDomain, domainType, Permit } = require('../../../helpers/eip712'); const { fromRpcSig } = require('ethereumjs-util'); const ethSigUtil = require('eth-sig-util'); @@ -58,16 +57,15 @@ contract('SafeERC20', function (accounts) { const spender = hasNoCode; beforeEach(async function () { - const chainId = await getChainId(); - this.token = await ERC20PermitNoRevertMock.new(); - this.data = { + this.data = await getDomain(this.token).then(domain => ({ primaryType: 'Permit', - types: { EIP712Domain, Permit }, - domain: { name: 'ERC20PermitNoRevertMock', version: '1', chainId, verifyingContract: this.token.address }, + types: { EIP712Domain: domainType(domain), Permit }, + domain, message: { owner, spender, value: '42', nonce: '0', deadline: constants.MAX_UINT256 }, - }; + })); + this.signature = fromRpcSig(ethSigUtil.signTypedMessage(wallet.getPrivateKey(), { data: this.data })); }); diff --git a/test/utils/cryptography/EIP712.test.js b/test/utils/cryptography/EIP712.test.js index 8c20b91ba..f12f22673 100644 --- a/test/utils/cryptography/EIP712.test.js +++ b/test/utils/cryptography/EIP712.test.js @@ -1,8 +1,9 @@ const ethSigUtil = require('eth-sig-util'); const Wallet = require('ethereumjs-wallet').default; -const { EIP712Domain, domainSeparator, hashTypedData } = require('../../helpers/eip712'); +const { getDomain, domainType, domainSeparator, hashTypedData } = require('../../helpers/eip712'); const { getChainId } = require('../../helpers/chainid'); +const { mapValues } = require('../../helpers/map-values'); const EIP712Verifier = artifacts.require('$EIP712Verifier'); @@ -21,19 +22,25 @@ contract('EIP712', function (accounts) { chainId: await getChainId(), verifyingContract: this.eip712.address, }; + this.domainType = domainType(this.domain); }); - it('domain separator', async function () { - const expected = await domainSeparator(this.domain); + describe('domain separator', function () { + it('is internally available', async function () { + const expected = await domainSeparator(this.domain); - expect(await this.eip712.$_domainSeparatorV4()).to.equal(expected); + expect(await this.eip712.$_domainSeparatorV4()).to.equal(expected); + }); + + it("can be rebuilt using EIP-5267's eip712Domain", async function () { + const rebuildDomain = await getDomain(this.eip712); + expect(mapValues(rebuildDomain, String)).to.be.deep.equal(mapValues(this.domain, String)); + }); }); it('hash digest', async function () { const structhash = web3.utils.randomHex(32); - const expected = await hashTypedData(this.domain, structhash); - - expect(await this.eip712.$_hashTypedDataV4(structhash)).to.be.equal(expected); + expect(await this.eip712.$_hashTypedDataV4(structhash)).to.be.equal(hashTypedData(this.domain, structhash)); }); it('digest', async function () { @@ -44,7 +51,7 @@ contract('EIP712', function (accounts) { const data = { types: { - EIP712Domain, + EIP712Domain: this.domainType, Mail: [ { name: 'to', type: 'address' }, { name: 'contents', type: 'string' }, From 5b027e517e6aee69f4b4b2f5e78274ac8ee53513 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Wed, 8 Feb 2023 22:03:27 +0100 Subject: [PATCH 026/133] Add missing `await` in tests (#4037) --- .../GovernorTimelockCompound.test.js | 2 +- .../GovernorTimelockControl.test.js | 2 +- test/token/ERC20/extensions/ERC4626.test.js | 100 +++++++++--------- 3 files changed, 52 insertions(+), 52 deletions(-) diff --git a/test/governance/extensions/GovernorTimelockCompound.test.js b/test/governance/extensions/GovernorTimelockCompound.test.js index fb6803383..446d74999 100644 --- a/test/governance/extensions/GovernorTimelockCompound.test.js +++ b/test/governance/extensions/GovernorTimelockCompound.test.js @@ -253,7 +253,7 @@ contract('GovernorTimelockCompound', function (accounts) { expect(await this.token.balanceOf(this.mock.address), 0); expect(await this.token.balanceOf(other), 1); - expectEvent.inTransaction(txExecute.tx, this.token, 'Transfer', { + await expectEvent.inTransaction(txExecute.tx, this.token, 'Transfer', { from: this.mock.address, to: other, value: '1', diff --git a/test/governance/extensions/GovernorTimelockControl.test.js b/test/governance/extensions/GovernorTimelockControl.test.js index 34fdfe92f..2a55787cb 100644 --- a/test/governance/extensions/GovernorTimelockControl.test.js +++ b/test/governance/extensions/GovernorTimelockControl.test.js @@ -264,7 +264,7 @@ contract('GovernorTimelockControl', function (accounts) { expect(await this.token.balanceOf(this.mock.address), 0); expect(await this.token.balanceOf(other), 1); - expectEvent.inTransaction(txExecute.tx, this.token, 'Transfer', { + await expectEvent.inTransaction(txExecute.tx, this.token, 'Transfer', { from: this.mock.address, to: other, value: '1', diff --git a/test/token/ERC20/extensions/ERC4626.test.js b/test/token/ERC20/extensions/ERC4626.test.js index f85ffd56d..5ed2aa132 100644 --- a/test/token/ERC20/extensions/ERC4626.test.js +++ b/test/token/ERC20/extensions/ERC4626.test.js @@ -49,13 +49,13 @@ contract('ERC4626', function (accounts) { const { tx } = await this.vault.deposit(parseToken(1), recipient, { from: holder }); - expectEvent.inTransaction(tx, this.token, 'Transfer', { + await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: holder, to: this.vault.address, value: parseToken(1), }); - expectEvent.inTransaction(tx, this.vault, 'Transfer', { + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { from: constants.ZERO_ADDRESS, to: recipient, value: parseShare(1), @@ -68,13 +68,13 @@ contract('ERC4626', function (accounts) { const { tx } = await this.vault.mint(parseShare(1), recipient, { from: holder }); - expectEvent.inTransaction(tx, this.token, 'Transfer', { + await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: holder, to: this.vault.address, value: parseToken(1), }); - expectEvent.inTransaction(tx, this.vault, 'Transfer', { + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { from: constants.ZERO_ADDRESS, to: recipient, value: parseShare(1), @@ -87,13 +87,13 @@ contract('ERC4626', function (accounts) { const { tx } = await this.vault.withdraw('0', recipient, holder, { from: holder }); - expectEvent.inTransaction(tx, this.token, 'Transfer', { + await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: this.vault.address, to: recipient, value: '0', }); - expectEvent.inTransaction(tx, this.vault, 'Transfer', { + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { from: holder, to: constants.ZERO_ADDRESS, value: '0', @@ -106,13 +106,13 @@ contract('ERC4626', function (accounts) { const { tx } = await this.vault.redeem('0', recipient, holder, { from: holder }); - expectEvent.inTransaction(tx, this.token, 'Transfer', { + await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: this.vault.address, to: recipient, value: '0', }); - expectEvent.inTransaction(tx, this.vault, 'Transfer', { + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { from: holder, to: constants.ZERO_ADDRESS, value: '0', @@ -135,13 +135,13 @@ contract('ERC4626', function (accounts) { const { tx } = await this.vault.deposit(parseToken(1), recipient, { from: holder }); - expectEvent.inTransaction(tx, this.token, 'Transfer', { + await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: holder, to: this.vault.address, value: parseToken(1), }); - expectEvent.inTransaction(tx, this.vault, 'Transfer', { + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { from: constants.ZERO_ADDRESS, to: recipient, value: parseShare(1), @@ -154,13 +154,13 @@ contract('ERC4626', function (accounts) { const { tx } = await this.vault.mint(parseShare(1), recipient, { from: holder }); - expectEvent.inTransaction(tx, this.token, 'Transfer', { + await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: holder, to: this.vault.address, value: parseToken(1), }); - expectEvent.inTransaction(tx, this.vault, 'Transfer', { + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { from: constants.ZERO_ADDRESS, to: recipient, value: parseShare(1), @@ -173,13 +173,13 @@ contract('ERC4626', function (accounts) { const { tx } = await this.vault.withdraw('0', recipient, holder, { from: holder }); - expectEvent.inTransaction(tx, this.token, 'Transfer', { + await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: this.vault.address, to: recipient, value: '0', }); - expectEvent.inTransaction(tx, this.vault, 'Transfer', { + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { from: holder, to: constants.ZERO_ADDRESS, value: '0', @@ -192,13 +192,13 @@ contract('ERC4626', function (accounts) { const { tx } = await this.vault.redeem('0', recipient, holder, { from: holder }); - expectEvent.inTransaction(tx, this.token, 'Transfer', { + await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: this.vault.address, to: recipient, value: '0', }); - expectEvent.inTransaction(tx, this.vault, 'Transfer', { + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { from: holder, to: constants.ZERO_ADDRESS, value: '0', @@ -221,16 +221,16 @@ contract('ERC4626', function (accounts) { // Can deposit 0 (max deposit) const { tx } = await this.vault.deposit(0, recipient, { from: holder }); - expectEvent.inTransaction(tx, this.token, 'Transfer', { + await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: holder, to: this.vault.address, - value: 0, + value: '0', }); - expectEvent.inTransaction(tx, this.vault, 'Transfer', { + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { from: constants.ZERO_ADDRESS, to: recipient, - value: 0, + value: '0', }); // Cannot deposit more than 0 @@ -247,13 +247,13 @@ contract('ERC4626', function (accounts) { const { tx } = await this.vault.mint(parseShare(1), recipient, { from: holder }); - expectEvent.inTransaction(tx, this.token, 'Transfer', { + await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: holder, to: this.vault.address, value: '0', }); - expectEvent.inTransaction(tx, this.vault, 'Transfer', { + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { from: constants.ZERO_ADDRESS, to: recipient, value: parseShare(1), @@ -267,13 +267,13 @@ contract('ERC4626', function (accounts) { const { tx } = await this.vault.withdraw('0', recipient, holder, { from: holder }); - expectEvent.inTransaction(tx, this.token, 'Transfer', { + await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: this.vault.address, to: recipient, value: '0', }); - expectEvent.inTransaction(tx, this.vault, 'Transfer', { + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { from: holder, to: constants.ZERO_ADDRESS, value: '0', @@ -286,13 +286,13 @@ contract('ERC4626', function (accounts) { const { tx } = await this.vault.redeem(parseShare(1), recipient, holder, { from: holder }); - expectEvent.inTransaction(tx, this.token, 'Transfer', { + await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: this.vault.address, to: recipient, value: '0', }); - expectEvent.inTransaction(tx, this.vault, 'Transfer', { + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { from: holder, to: constants.ZERO_ADDRESS, value: parseShare(1), @@ -316,13 +316,13 @@ contract('ERC4626', function (accounts) { const { tx } = await this.vault.deposit(parseToken(1), recipient, { from: holder }); - expectEvent.inTransaction(tx, this.token, 'Transfer', { + await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: holder, to: this.vault.address, value: parseToken(1), }); - expectEvent.inTransaction(tx, this.vault, 'Transfer', { + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { from: constants.ZERO_ADDRESS, to: recipient, value: parseShare(100), @@ -335,13 +335,13 @@ contract('ERC4626', function (accounts) { const { tx } = await this.vault.mint(parseShare(1), recipient, { from: holder }); - expectEvent.inTransaction(tx, this.token, 'Transfer', { + await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: holder, to: this.vault.address, value: parseToken(1).divn(100), }); - expectEvent.inTransaction(tx, this.vault, 'Transfer', { + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { from: constants.ZERO_ADDRESS, to: recipient, value: parseShare(1), @@ -354,13 +354,13 @@ contract('ERC4626', function (accounts) { const { tx } = await this.vault.withdraw(parseToken(1), recipient, holder, { from: holder }); - expectEvent.inTransaction(tx, this.token, 'Transfer', { + await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: this.vault.address, to: recipient, value: parseToken(1), }); - expectEvent.inTransaction(tx, this.vault, 'Transfer', { + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { from: holder, to: constants.ZERO_ADDRESS, value: parseShare(100), @@ -382,13 +382,13 @@ contract('ERC4626', function (accounts) { const { tx } = await this.vault.redeem(parseShare(100), recipient, holder, { from: holder }); - expectEvent.inTransaction(tx, this.token, 'Transfer', { + await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: this.vault.address, to: recipient, value: parseToken(1), }); - expectEvent.inTransaction(tx, this.vault, 'Transfer', { + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { from: holder, to: constants.ZERO_ADDRESS, value: parseShare(100), @@ -420,12 +420,12 @@ contract('ERC4626', function (accounts) { // 1. Alice mints 2000 shares (costs 2000 tokens) { const { tx } = await this.vault.mint(2000, user1, { from: user1 }); - expectEvent.inTransaction(tx, this.token, 'Transfer', { + await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: user1, to: this.vault.address, value: '2000', }); - expectEvent.inTransaction(tx, this.vault, 'Transfer', { + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { from: constants.ZERO_ADDRESS, to: user1, value: '2000', @@ -443,12 +443,12 @@ contract('ERC4626', function (accounts) { // 2. Bob deposits 4000 tokens (mints 4000 shares) { const { tx } = await this.vault.mint(4000, user2, { from: user2 }); - expectEvent.inTransaction(tx, this.token, 'Transfer', { + await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: user2, to: this.vault.address, value: '4000', }); - expectEvent.inTransaction(tx, this.vault, 'Transfer', { + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { from: constants.ZERO_ADDRESS, to: user2, value: '4000', @@ -476,12 +476,12 @@ contract('ERC4626', function (accounts) { // 4. Alice deposits 2000 tokens (mints 1333 shares) { const { tx } = await this.vault.deposit(2000, user1, { from: user1 }); - expectEvent.inTransaction(tx, this.token, 'Transfer', { + await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: user1, to: this.vault.address, value: '2000', }); - expectEvent.inTransaction(tx, this.vault, 'Transfer', { + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { from: constants.ZERO_ADDRESS, to: user1, value: '1333', @@ -500,12 +500,12 @@ contract('ERC4626', function (accounts) { // NOTE: Alices's vault assets got rounded up { const { tx } = await this.vault.mint(2000, user2, { from: user2 }); - expectEvent.inTransaction(tx, this.token, 'Transfer', { + await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: user2, to: this.vault.address, value: '3001', }); - expectEvent.inTransaction(tx, this.vault, 'Transfer', { + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { from: constants.ZERO_ADDRESS, to: user2, value: '2000', @@ -533,12 +533,12 @@ contract('ERC4626', function (accounts) { // 7. Alice redeem 1333 shares (2428 assets) { const { tx } = await this.vault.redeem(1333, user1, user1, { from: user1 }); - expectEvent.inTransaction(tx, this.vault, 'Transfer', { + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { from: user1, to: constants.ZERO_ADDRESS, value: '1333', }); - expectEvent.inTransaction(tx, this.token, 'Transfer', { + await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: this.vault.address, to: user1, value: '2428', @@ -555,12 +555,12 @@ contract('ERC4626', function (accounts) { // 8. Bob withdraws 2929 assets (1608 shares) { const { tx } = await this.vault.withdraw(2929, user2, user2, { from: user2 }); - expectEvent.inTransaction(tx, this.vault, 'Transfer', { + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { from: user2, to: constants.ZERO_ADDRESS, value: '1608', }); - expectEvent.inTransaction(tx, this.token, 'Transfer', { + await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: this.vault.address, to: user2, value: '2929', @@ -578,12 +578,12 @@ contract('ERC4626', function (accounts) { // NOTE: Bob's assets have been rounded back up { const { tx } = await this.vault.withdraw(3643, user1, user1, { from: user1 }); - expectEvent.inTransaction(tx, this.vault, 'Transfer', { + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { from: user1, to: constants.ZERO_ADDRESS, value: '2000', }); - expectEvent.inTransaction(tx, this.token, 'Transfer', { + await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: this.vault.address, to: user1, value: '3643', @@ -600,12 +600,12 @@ contract('ERC4626', function (accounts) { // 10. Bob redeem 4392 shares (8001 tokens) { const { tx } = await this.vault.redeem(4392, user2, user2, { from: user2 }); - expectEvent.inTransaction(tx, this.vault, 'Transfer', { + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { from: user2, to: constants.ZERO_ADDRESS, value: '4392', }); - expectEvent.inTransaction(tx, this.token, 'Transfer', { + await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: this.vault.address, to: user2, value: '8001', From 94cd8ef12e0ee6d6a929eae83e28598e5d017270 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Garc=C3=ADa?= Date: Thu, 9 Feb 2023 13:43:34 -0600 Subject: [PATCH 027/133] Add ERC721 Wrapper (#3863) Co-authored-by: Hadrien Croubois --- .changeset/early-oranges-raise.md | 5 + contracts/token/ERC721/README.adoc | 3 + .../token/ERC721/extensions/ERC721Wrapper.sol | 102 ++++++ docs/modules/ROOT/pages/governance.adoc | 2 +- test/token/ERC721/ERC721.behavior.js | 5 +- .../ERC721/extensions/ERC721Wrapper.test.js | 338 ++++++++++++++++++ 6 files changed, 452 insertions(+), 3 deletions(-) create mode 100644 .changeset/early-oranges-raise.md create mode 100644 contracts/token/ERC721/extensions/ERC721Wrapper.sol create mode 100644 test/token/ERC721/extensions/ERC721Wrapper.test.js diff --git a/.changeset/early-oranges-raise.md b/.changeset/early-oranges-raise.md new file mode 100644 index 000000000..af60a4432 --- /dev/null +++ b/.changeset/early-oranges-raise.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': minor +--- + +`ERC721Wrapper`: add a new extension of the `ERC721` token which wraps an underlying token. Deposit and withdraw guarantee that the ownership of each token is backed by a corresponding underlying token with the same identifier. diff --git a/contracts/token/ERC721/README.adoc b/contracts/token/ERC721/README.adoc index b3377afef..f571f5c57 100644 --- a/contracts/token/ERC721/README.adoc +++ b/contracts/token/ERC721/README.adoc @@ -28,6 +28,7 @@ Additionally there are a few of other extensions: * {ERC721Royalty}: A way to signal royalty information following ERC2981. * {ERC721Pausable}: A primitive to pause contract operation. * {ERC721Burnable}: A way for token holders to burn their own tokens. +* {ERC721Wrapper}: Wrapper to create an ERC721 backed by another ERC721, with deposit and withdraw methods. Useful in conjunction with {ERC721Votes}. NOTE: This core set of contracts is designed to be unopinionated, allowing developers to access the internal functions in ERC721 (such as <>) and expose them as external functions in the way they prefer. On the other hand, xref:ROOT:erc721.adoc#Presets[ERC721 Presets] (such as {ERC721PresetMinterPauserAutoId}) are designed using opinionated patterns to provide developers with ready to use, deployable contracts. @@ -59,6 +60,8 @@ NOTE: This core set of contracts is designed to be unopinionated, allowing devel {{ERC721Royalty}} +{{ERC721Wrapper}} + == Presets These contracts are preconfigured combinations of the above features. They can be used through inheritance or as models to copy and paste their source code. diff --git a/contracts/token/ERC721/extensions/ERC721Wrapper.sol b/contracts/token/ERC721/extensions/ERC721Wrapper.sol new file mode 100644 index 000000000..87729188a --- /dev/null +++ b/contracts/token/ERC721/extensions/ERC721Wrapper.sol @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../ERC721.sol"; +import "../utils/ERC721Holder.sol"; + +/** + * @dev Extension of the ERC721 token contract to support token wrapping. + * + * Users can deposit and withdraw an "underlying token" and receive a "wrapped token" with a matching tokenId. This is useful + * in conjunction with other modules. For example, combining this wrapping mechanism with {ERC721Votes} will allow the + * wrapping of an existing "basic" ERC721 into a governance token. + * + * _Available since v4.9.0_ + */ +abstract contract ERC721Wrapper is ERC721, ERC721Holder { + IERC721 private immutable _underlying; + + // Kept as bytes12 so it can be packed with an address + // Equal to 0xb125e89df18e2ceac5fd2fa8 + bytes12 public constant WRAPPER_ACCEPT_MAGIC = bytes12(keccak256("WRAPPER_ACCEPT_MAGIC")); + + constructor(IERC721 underlyingToken) { + _underlying = underlyingToken; + } + + /** + * @dev Allow a user to deposit underlying tokens and mint the corresponding tokenIds. + */ + function depositFor(address account, uint256[] memory tokenIds) public virtual returns (bool) { + bytes memory data = abi.encodePacked(WRAPPER_ACCEPT_MAGIC, account); + + uint256 length = tokenIds.length; + for (uint256 i = 0; i < length; ++i) { + underlying().safeTransferFrom(_msgSender(), address(this), tokenIds[i], data); + } + + return true; + } + + /** + * @dev Allow a user to burn wrapped tokens and withdraw the corresponding tokenIds of the underlying tokens. + */ + function withdrawTo(address account, uint256[] memory tokenIds) public virtual returns (bool) { + uint256 length = tokenIds.length; + for (uint256 i = 0; i < length; ++i) { + uint256 tokenId = tokenIds[i]; + require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721Wrapper: caller is not token owner or approved"); + _burn(tokenId); + // Checks were already performed at this point, and there's no way to retake ownership or approval from + // the wrapped tokenId after this point, so it's safe to remove the reentrancy check for the next line. + // slither-disable-next-line reentrancy-no-eth + underlying().safeTransferFrom(address(this), account, tokenId); + } + + return true; + } + + /** + * @dev Overrides {IERC721Receiver-onERC721Received} to allow minting on direct ERC721 transfers to + * this contract. + * + * In case there's data attached, it validates that the sender is aware of this contract's existence and behavior + * by checking a magic value (`WRAPPER_ACCEPT_MAGIC`) in the first 12 bytes. If it also matches, the rest 20 + * bytes are used as an address to send the tokens to. + * + * WARNING: Doesn't work with unsafe transfers (eg. {IERC721-transferFrom}). Use {ERC721Wrapper-_recover} + * for recovering in that scenario. + */ + function onERC721Received( + address, + address from, + uint256 tokenId, + bytes memory data + ) public override returns (bytes4) { + require(address(underlying()) == _msgSender(), "ERC721Wrapper: caller is not underlying"); + if (data.length > 0) { + require(data.length == 32 && WRAPPER_ACCEPT_MAGIC == bytes12(data), "ERC721Wrapper: Invalid data format"); + from = address(bytes20(bytes32(data) << 96)); + } + _safeMint(from, tokenId); + return IERC721Receiver.onERC721Received.selector; + } + + /** + * @dev Mint a wrapped token to cover any underlyingToken that would have been transferred by mistake. Internal + * function that can be exposed with access control if desired. + */ + function _recover(address account, uint256 tokenId) internal virtual returns (uint256) { + require(underlying().ownerOf(tokenId) == address(this), "ERC721Wrapper: wrapper is not token owner"); + _safeMint(account, tokenId); + return tokenId; + } + + /** + * @dev Returns the underlying token. + */ + function underlying() public view virtual returns (IERC721) { + return _underlying; + } +} diff --git a/docs/modules/ROOT/pages/governance.adoc b/docs/modules/ROOT/pages/governance.adoc index 358a63e90..eb76321bf 100644 --- a/docs/modules/ROOT/pages/governance.adoc +++ b/docs/modules/ROOT/pages/governance.adoc @@ -119,7 +119,7 @@ contract MyToken is ERC20, ERC20Permit, ERC20Votes, ERC20Wrapper { } ``` -NOTE: Voting power could be determined in different ways: multiple ERC20 tokens, ERC721 tokens, sybil resistant identities, etc. All of these options are potentially supported by writing a custom Votes module for your Governor. The only other source of voting power available in OpenZeppelin Contracts currently is xref:api:token/ERC721.adoc#ERC721Votes[`ERC721Votes`]. +NOTE:The only other source of voting power available in OpenZeppelin Contracts currently is xref:api:token/ERC721.adoc#ERC721Votes[`ERC721Votes`]. ERC721 tokens that don't provide this functionality can be wrapped into a voting tokens using a combination of xref:api:token/ERC721.adoc#ERC721Votes[`ERC721Votes`] and xref:api:token/ERC721Wrapper.adoc#ERC721Wrapper[`ERC721Wrapper`]. === Governor diff --git a/test/token/ERC721/ERC721.behavior.js b/test/token/ERC721/ERC721.behavior.js index c09479572..6867db31f 100644 --- a/test/token/ERC721/ERC721.behavior.js +++ b/test/token/ERC721/ERC721.behavior.js @@ -5,6 +5,7 @@ const { ZERO_ADDRESS } = constants; const { shouldSupportInterfaces } = require('../../utils/introspection/SupportsInterface.behavior'); const ERC721ReceiverMock = artifacts.require('ERC721ReceiverMock'); +const NonERC721ReceiverMock = artifacts.require('CallReceiverMock'); const Error = ['None', 'RevertWithMessage', 'RevertWithoutMessage', 'Panic'].reduce( (acc, entry, idx) => Object.assign({ [entry]: idx }, acc), @@ -316,7 +317,7 @@ function shouldBehaveLikeERC721(errorPrefix, owner, newOwner, approved, anotherA describe('to a contract that does not implement the required function', function () { it('reverts', async function () { - const nonReceiver = this.token; + const nonReceiver = await NonERC721ReceiverMock.new(); await expectRevert( this.token.safeTransferFrom(owner, nonReceiver.address, tokenId, { from: owner }), 'ERC721: transfer to non ERC721Receiver implementer', @@ -392,7 +393,7 @@ function shouldBehaveLikeERC721(errorPrefix, owner, newOwner, approved, anotherA context('to a contract that does not implement the required function', function () { it('reverts', async function () { - const nonReceiver = this.token; + const nonReceiver = await NonERC721ReceiverMock.new(); await expectRevert( this.token.$_safeMint(nonReceiver.address, tokenId), 'ERC721: transfer to non ERC721Receiver implementer', diff --git a/test/token/ERC721/extensions/ERC721Wrapper.test.js b/test/token/ERC721/extensions/ERC721Wrapper.test.js new file mode 100644 index 000000000..5c83d73cc --- /dev/null +++ b/test/token/ERC721/extensions/ERC721Wrapper.test.js @@ -0,0 +1,338 @@ +const { BN, expectEvent, constants, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { keccakFromString, bufferToHex } = require('ethereumjs-util'); + +const { shouldBehaveLikeERC721 } = require('../ERC721.behavior'); + +const ERC721 = artifacts.require('$ERC721'); +const ERC721Wrapper = artifacts.require('$ERC721Wrapper'); + +contract('ERC721Wrapper', function (accounts) { + const [initialHolder, anotherAccount, approvedAccount] = accounts; + + const name = 'My Token'; + const symbol = 'MTKN'; + const firstTokenId = new BN(1); + const secondTokenId = new BN(2); + + beforeEach(async function () { + this.underlying = await ERC721.new(name, symbol); + this.token = await ERC721Wrapper.new(`Wrapped ${name}`, `W${symbol}`, this.underlying.address); + + await this.underlying.$_safeMint(initialHolder, firstTokenId); + await this.underlying.$_safeMint(initialHolder, secondTokenId); + }); + + it('has a name', async function () { + expect(await this.token.name()).to.equal(`Wrapped ${name}`); + }); + + it('has a symbol', async function () { + expect(await this.token.symbol()).to.equal(`W${symbol}`); + }); + + it('has underlying', async function () { + expect(await this.token.underlying()).to.be.bignumber.equal(this.underlying.address); + }); + + describe('depositFor', function () { + it('works with token approval', async function () { + await this.underlying.approve(this.token.address, firstTokenId, { from: initialHolder }); + + const { tx } = await this.token.depositFor(initialHolder, [firstTokenId], { from: initialHolder }); + + await expectEvent.inTransaction(tx, this.underlying, 'Transfer', { + from: initialHolder, + to: this.token.address, + tokenId: firstTokenId, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: constants.ZERO_ADDRESS, + to: initialHolder, + tokenId: firstTokenId, + }); + }); + + it('works with approval for all', async function () { + await this.underlying.setApprovalForAll(this.token.address, true, { from: initialHolder }); + + const { tx } = await this.token.depositFor(initialHolder, [firstTokenId], { from: initialHolder }); + + await expectEvent.inTransaction(tx, this.underlying, 'Transfer', { + from: initialHolder, + to: this.token.address, + tokenId: firstTokenId, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: constants.ZERO_ADDRESS, + to: initialHolder, + tokenId: firstTokenId, + }); + }); + + it('works sending to another account', async function () { + await this.underlying.approve(this.token.address, firstTokenId, { from: initialHolder }); + + const { tx } = await this.token.depositFor(anotherAccount, [firstTokenId], { from: initialHolder }); + + await expectEvent.inTransaction(tx, this.underlying, 'Transfer', { + from: initialHolder, + to: this.token.address, + tokenId: firstTokenId, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: constants.ZERO_ADDRESS, + to: anotherAccount, + tokenId: firstTokenId, + }); + }); + + it('works with multiple tokens', async function () { + await this.underlying.approve(this.token.address, firstTokenId, { from: initialHolder }); + await this.underlying.approve(this.token.address, secondTokenId, { from: initialHolder }); + + const { tx } = await this.token.depositFor(initialHolder, [firstTokenId, secondTokenId], { from: initialHolder }); + + await expectEvent.inTransaction(tx, this.underlying, 'Transfer', { + from: initialHolder, + to: this.token.address, + tokenId: firstTokenId, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: constants.ZERO_ADDRESS, + to: initialHolder, + tokenId: firstTokenId, + }); + await expectEvent.inTransaction(tx, this.underlying, 'Transfer', { + from: initialHolder, + to: this.token.address, + tokenId: secondTokenId, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: constants.ZERO_ADDRESS, + to: initialHolder, + tokenId: secondTokenId, + }); + }); + + it('reverts with missing approval', async function () { + await expectRevert( + this.token.depositFor(initialHolder, [firstTokenId], { from: initialHolder }), + 'ERC721: caller is not token owner or approved', + ); + }); + }); + + describe('withdrawTo', function () { + beforeEach(async function () { + await this.underlying.approve(this.token.address, firstTokenId, { from: initialHolder }); + await this.token.depositFor(initialHolder, [firstTokenId], { from: initialHolder }); + }); + + it('works for an owner', async function () { + const { tx } = await this.token.withdrawTo(initialHolder, [firstTokenId], { from: initialHolder }); + + await expectEvent.inTransaction(tx, this.underlying, 'Transfer', { + from: this.token.address, + to: initialHolder, + tokenId: firstTokenId, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: initialHolder, + to: constants.ZERO_ADDRESS, + tokenId: firstTokenId, + }); + }); + + it('works for an approved', async function () { + await this.token.approve(approvedAccount, firstTokenId, { from: initialHolder }); + + const { tx } = await this.token.withdrawTo(initialHolder, [firstTokenId], { from: approvedAccount }); + + await expectEvent.inTransaction(tx, this.underlying, 'Transfer', { + from: this.token.address, + to: initialHolder, + tokenId: firstTokenId, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: initialHolder, + to: constants.ZERO_ADDRESS, + tokenId: firstTokenId, + }); + }); + + it('works for an approved for all', async function () { + await this.token.setApprovalForAll(approvedAccount, true, { from: initialHolder }); + + const { tx } = await this.token.withdrawTo(initialHolder, [firstTokenId], { from: approvedAccount }); + + await expectEvent.inTransaction(tx, this.underlying, 'Transfer', { + from: this.token.address, + to: initialHolder, + tokenId: firstTokenId, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: initialHolder, + to: constants.ZERO_ADDRESS, + tokenId: firstTokenId, + }); + }); + + it("doesn't work for a non-owner nor approved", async function () { + await expectRevert( + this.token.withdrawTo(initialHolder, [firstTokenId], { from: anotherAccount }), + 'ERC721Wrapper: caller is not token owner or approved', + ); + }); + + it('works with multiple tokens', async function () { + await this.underlying.approve(this.token.address, secondTokenId, { from: initialHolder }); + await this.token.depositFor(initialHolder, [secondTokenId], { from: initialHolder }); + + const { tx } = await this.token.withdrawTo(initialHolder, [firstTokenId, secondTokenId], { from: initialHolder }); + + await expectEvent.inTransaction(tx, this.underlying, 'Transfer', { + from: this.token.address, + to: initialHolder, + tokenId: firstTokenId, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: initialHolder, + to: constants.ZERO_ADDRESS, + tokenId: firstTokenId, + }); + }); + + it('works to another account', async function () { + const { tx } = await this.token.withdrawTo(anotherAccount, [firstTokenId], { from: initialHolder }); + + await expectEvent.inTransaction(tx, this.underlying, 'Transfer', { + from: this.token.address, + to: anotherAccount, + tokenId: firstTokenId, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: initialHolder, + to: constants.ZERO_ADDRESS, + tokenId: firstTokenId, + }); + }); + }); + + describe('onERC721Received', function () { + const WRAPPER_ACCEPT_MAGIC = bufferToHex(keccakFromString('WRAPPER_ACCEPT_MAGIC')).slice(0, 26); // Include 0x + + const magicWithAddresss = address => + web3.utils.encodePacked( + { + value: WRAPPER_ACCEPT_MAGIC, + type: 'bytes12', + }, + { + value: address, + type: 'address', + }, + ); + + it('only allows calls from underlying', async function () { + await expectRevert( + this.token.onERC721Received( + initialHolder, + this.token.address, + firstTokenId, + magicWithAddresss(anotherAccount), // Correct data + { from: anotherAccount }, + ), + 'ERC721Wrapper: caller is not underlying', + ); + }); + + describe('when data length is > 0', function () { + it('reverts with arbitrary data', async function () { + await expectRevert( + this.underlying.methods['safeTransferFrom(address,address,uint256,bytes)']( + initialHolder, + this.token.address, + firstTokenId, + '0x0123', + { + from: initialHolder, + }, + ), + 'ERC721Wrapper: Invalid data format', + ); + }); + + it('reverts with the magic value and data length different to 32', async function () { + await expectRevert( + this.underlying.methods['safeTransferFrom(address,address,uint256,bytes)']( + initialHolder, + this.token.address, + firstTokenId, + WRAPPER_ACCEPT_MAGIC, // Reverts for any non-32 bytes value + { + from: initialHolder, + }, + ), + 'ERC721Wrapper: Invalid data format', + ); + }); + + it('mints token to specific holder with address after magic value', async function () { + const { tx } = await this.underlying.methods['safeTransferFrom(address,address,uint256,bytes)']( + initialHolder, + this.token.address, + firstTokenId, + magicWithAddresss(anotherAccount), + { + from: initialHolder, + }, + ); + + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: constants.ZERO_ADDRESS, + to: anotherAccount, + tokenId: firstTokenId, + }); + }); + }); + + it('mints a token to from if no data is specified', async function () { + const { tx } = await this.underlying.safeTransferFrom(initialHolder, this.token.address, firstTokenId, { + from: initialHolder, + }); + + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: constants.ZERO_ADDRESS, + to: initialHolder, + tokenId: firstTokenId, + }); + }); + }); + + describe('_recover', function () { + it('works if there is something to recover', async function () { + // Should use `transferFrom` to avoid `onERC721Received` minting + await this.underlying.transferFrom(initialHolder, this.token.address, firstTokenId, { from: initialHolder }); + + const { tx } = await this.token.$_recover(anotherAccount, firstTokenId); + + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: constants.ZERO_ADDRESS, + to: anotherAccount, + tokenId: firstTokenId, + }); + }); + + it('reverts if there is nothing to recover', async function () { + await expectRevert( + this.token.$_recover(initialHolder, firstTokenId), + 'ERC721Wrapper: wrapper is not token owner', + ); + }); + }); + + describe('ERC712 behavior', function () { + shouldBehaveLikeERC721('ERC721', ...accounts); + }); +}); From 790cc5b65a66e0515bcbf97c430975bb7fbef8f7 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Thu, 9 Feb 2023 22:33:55 +0100 Subject: [PATCH 028/133] Add timestamp based governor with EIP-6372 and EIP-5805 (#3934) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Francisco Giordano Co-authored-by: Ernesto García Co-authored-by: Francisco --- .changeset/four-bats-sniff.md | 5 + .changeset/ninety-hornets-kick.md | 5 + .github/actions/storage-layout/action.yml | 2 +- contracts/governance/Governor.sol | 85 +- contracts/governance/IGovernor.sol | 62 +- contracts/governance/README.adoc | 6 +- .../GovernorCompatibilityBravo.sol | 6 +- .../extensions/GovernorPreventLateQuorum.sol | 19 +- .../extensions/GovernorTimelockCompound.sol | 17 +- .../governance/extensions/GovernorVotes.sol | 34 +- .../extensions/GovernorVotesComp.sol | 30 +- .../GovernorVotesQuorumFraction.sol | 29 +- contracts/governance/utils/IVotes.sol | 10 +- contracts/governance/utils/Votes.sol | 81 +- contracts/interfaces/IERC5805.sol | 9 + contracts/interfaces/IERC6372.sol | 17 + contracts/mocks/VotesMock.sol | 11 + .../mocks/token/ERC20VotesLegacyMock.sol | 262 ++++ contracts/mocks/token/VotesTimestamp.sol | 40 + .../token/ERC20/extensions/ERC20Votes.sol | 63 +- contracts/utils/Checkpoints.sol | 50 + scripts/checks/compare-layout.js | 1 - scripts/checks/compareGasReports.js | 16 +- scripts/generate/templates/Checkpoints.js | 66 +- test/governance/Governor.test.js | 1266 +++++++++-------- .../GovernorCompatibilityBravo.test.js | 425 +++--- .../extensions/GovernorComp.test.js | 115 +- .../extensions/GovernorERC721.test.js | 172 +-- .../GovernorPreventLateQuorum.test.js | 309 ++-- .../GovernorTimelockCompound.test.js | 577 ++++---- .../GovernorTimelockControl.test.js | 729 +++++----- .../GovernorVotesQuorumFraction.test.js | 242 ++-- .../extensions/GovernorWithParams.test.js | 252 ++-- test/governance/utils/EIP6372.behavior.js | 23 + test/governance/utils/Votes.behavior.js | 91 +- test/governance/utils/Votes.test.js | 99 +- test/helpers/governance.js | 15 +- test/helpers/time.js | 16 + .../token/ERC20/extensions/ERC20Votes.test.js | 1036 +++++++------- .../ERC20/extensions/ERC20VotesComp.test.js | 967 ++++++------- .../ERC721/extensions/ERC721Votes.test.js | 1 + test/utils/Checkpoints.test.js | 29 +- 42 files changed, 4081 insertions(+), 3209 deletions(-) create mode 100644 .changeset/four-bats-sniff.md create mode 100644 .changeset/ninety-hornets-kick.md create mode 100644 contracts/interfaces/IERC5805.sol create mode 100644 contracts/interfaces/IERC6372.sol create mode 100644 contracts/mocks/token/ERC20VotesLegacyMock.sol create mode 100644 contracts/mocks/token/VotesTimestamp.sol create mode 100644 test/governance/utils/EIP6372.behavior.js create mode 100644 test/helpers/time.js diff --git a/.changeset/four-bats-sniff.md b/.changeset/four-bats-sniff.md new file mode 100644 index 000000000..137b5e515 --- /dev/null +++ b/.changeset/four-bats-sniff.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': minor +--- + +`Governor`: Enable timestamp operation for blockchains without a stable block time. This is achieved by connecting a Governor's internal clock to match a voting token's EIP-6372 interface. diff --git a/.changeset/ninety-hornets-kick.md b/.changeset/ninety-hornets-kick.md new file mode 100644 index 000000000..16886c5c1 --- /dev/null +++ b/.changeset/ninety-hornets-kick.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': minor +--- + +`Votes`, `ERC20Votes`, `ERC721Votes`: support timestamp checkpointing using EIP-6372. diff --git a/.github/actions/storage-layout/action.yml b/.github/actions/storage-layout/action.yml index e3e104a01..fdfd5a25b 100644 --- a/.github/actions/storage-layout/action.yml +++ b/.github/actions/storage-layout/action.yml @@ -40,7 +40,7 @@ runs: - name: Compare layouts if: steps.reference.outcome == 'success' && github.event_name == 'pull_request' run: | - node scripts/checks/compare-layout.js --head ${{ inputs.layout }} --ref ${{ inputs.ref_layout }} >> $GITHUB_STEP_SUMMARY + node scripts/checks/compare-layout.js --head ${{ inputs.layout }} --ref ${{ inputs.ref_layout }} shell: bash - name: Rename artifacts for upload if: github.event_name != 'pull_request' diff --git a/contracts/governance/Governor.sol b/contracts/governance/Governor.sol index f82f9fea8..e3691a3ed 100644 --- a/contracts/governance/Governor.sol +++ b/contracts/governance/Governor.sol @@ -12,7 +12,6 @@ import "../utils/math/SafeCast.sol"; import "../utils/structs/DoubleEndedQueue.sol"; import "../utils/Address.sol"; import "../utils/Context.sol"; -import "../utils/Timers.sol"; import "./IGovernor.sol"; /** @@ -29,22 +28,29 @@ import "./IGovernor.sol"; abstract contract Governor is Context, ERC165, EIP712, IGovernor, IERC721Receiver, IERC1155Receiver { using DoubleEndedQueue for DoubleEndedQueue.Bytes32Deque; using SafeCast for uint256; - using Timers for Timers.BlockNumber; bytes32 public constant BALLOT_TYPEHASH = keccak256("Ballot(uint256 proposalId,uint8 support)"); bytes32 public constant EXTENDED_BALLOT_TYPEHASH = keccak256("ExtendedBallot(uint256 proposalId,uint8 support,string reason,bytes params)"); + // solhint-disable var-name-mixedcase struct ProposalCore { - Timers.BlockNumber voteStart; - Timers.BlockNumber voteEnd; + // --- start retyped from Timers.BlockNumber at offset 0x00 --- + uint64 voteStart; + address proposer; + bytes4 __gap_unused0; + // --- start retyped from Timers.BlockNumber at offset 0x20 --- + uint64 voteEnd; + bytes24 __gap_unused1; + // --- Remaining fields starting at offset 0x40 --------------- bool executed; bool canceled; - address proposer; } + // solhint-enable var-name-mixedcase string private _name; + /// @custom:oz-retyped-from mapping(uint256 => Governor.ProposalCore) mapping(uint256 => ProposalCore) private _proposals; // This queue keeps track of the governor operating on itself. Calls to functions protected by the @@ -96,12 +102,13 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor, IERC721Receive return interfaceId == (type(IGovernor).interfaceId ^ + type(IERC6372).interfaceId ^ this.cancel.selector ^ this.castVoteWithReasonAndParams.selector ^ this.castVoteWithReasonAndParamsBySig.selector ^ this.getVotesWithParams.selector) || - interfaceId == (type(IGovernor).interfaceId ^ this.cancel.selector) || - interfaceId == type(IGovernor).interfaceId || + // Previous interface for backwards compatibility + interfaceId == (type(IGovernor).interfaceId ^ type(IERC6372).interfaceId ^ this.cancel.selector) || interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId); } @@ -162,13 +169,15 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor, IERC721Receive revert("Governor: unknown proposal id"); } - if (snapshot >= block.number) { + uint256 currentTimepoint = clock(); + + if (snapshot >= currentTimepoint) { return ProposalState.Pending; } uint256 deadline = proposalDeadline(proposalId); - if (deadline >= block.number) { + if (deadline >= currentTimepoint) { return ProposalState.Active; } @@ -179,25 +188,32 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor, IERC721Receive } } + /** + * @dev Part of the Governor Bravo's interface: _"The number of votes required in order for a voter to become a proposer"_. + */ + function proposalThreshold() public view virtual returns (uint256) { + return 0; + } + /** * @dev See {IGovernor-proposalSnapshot}. */ function proposalSnapshot(uint256 proposalId) public view virtual override returns (uint256) { - return _proposals[proposalId].voteStart.getDeadline(); + return _proposals[proposalId].voteStart; } /** * @dev See {IGovernor-proposalDeadline}. */ function proposalDeadline(uint256 proposalId) public view virtual override returns (uint256) { - return _proposals[proposalId].voteEnd.getDeadline(); + return _proposals[proposalId].voteEnd; } /** - * @dev Part of the Governor Bravo's interface: _"The number of votes required in order for a voter to become a proposer"_. + * @dev Address of the proposer */ - function proposalThreshold() public view virtual returns (uint256) { - return 0; + function _proposalProposer(uint256 proposalId) internal view virtual returns (address) { + return _proposals[proposalId].proposer; } /** @@ -211,13 +227,9 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor, IERC721Receive function _voteSucceeded(uint256 proposalId) internal view virtual returns (bool); /** - * @dev Get the voting weight of `account` at a specific `blockNumber`, for a vote as described by `params`. + * @dev Get the voting weight of `account` at a specific `timepoint`, for a vote as described by `params`. */ - function _getVotes( - address account, - uint256 blockNumber, - bytes memory params - ) internal view virtual returns (uint256); + function _getVotes(address account, uint256 timepoint, bytes memory params) internal view virtual returns (uint256); /** * @dev Register a vote for `proposalId` by `account` with a given `support`, voting `weight` and voting `params`. @@ -252,9 +264,10 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor, IERC721Receive string memory description ) public virtual override returns (uint256) { address proposer = _msgSender(); + uint256 currentTimepoint = clock(); require( - getVotes(proposer, block.number - 1) >= proposalThreshold(), + getVotes(proposer, currentTimepoint - 1) >= proposalThreshold(), "Governor: proposer votes below proposal threshold" ); @@ -263,16 +276,20 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor, IERC721Receive require(targets.length == values.length, "Governor: invalid proposal length"); require(targets.length == calldatas.length, "Governor: invalid proposal length"); require(targets.length > 0, "Governor: empty proposal"); + require(_proposals[proposalId].proposer == address(0), "Governor: proposal already exists"); - ProposalCore storage proposal = _proposals[proposalId]; - require(proposal.voteStart.isUnset(), "Governor: proposal already exists"); + uint256 snapshot = currentTimepoint + votingDelay(); + uint256 deadline = snapshot + votingPeriod(); - uint64 snapshot = block.number.toUint64() + votingDelay().toUint64(); - uint64 deadline = snapshot + votingPeriod().toUint64(); - - proposal.voteStart.setDeadline(snapshot); - proposal.voteEnd.setDeadline(deadline); - proposal.proposer = proposer; + _proposals[proposalId] = ProposalCore({ + proposer: proposer, + voteStart: snapshot.toUint64(), + voteEnd: deadline.toUint64(), + executed: false, + canceled: false, + __gap_unused0: 0, + __gap_unused1: 0 + }); emit ProposalCreated( proposalId, @@ -416,8 +433,8 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor, IERC721Receive /** * @dev See {IGovernor-getVotes}. */ - function getVotes(address account, uint256 blockNumber) public view virtual override returns (uint256) { - return _getVotes(account, blockNumber, _defaultParams()); + function getVotes(address account, uint256 timepoint) public view virtual override returns (uint256) { + return _getVotes(account, timepoint, _defaultParams()); } /** @@ -425,10 +442,10 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor, IERC721Receive */ function getVotesWithParams( address account, - uint256 blockNumber, + uint256 timepoint, bytes memory params ) public view virtual override returns (uint256) { - return _getVotes(account, blockNumber, params); + return _getVotes(account, timepoint, params); } /** @@ -546,7 +563,7 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor, IERC721Receive ProposalCore storage proposal = _proposals[proposalId]; require(state(proposalId) == ProposalState.Active, "Governor: vote not currently active"); - uint256 weight = _getVotes(account, proposal.voteStart.getDeadline(), params); + uint256 weight = _getVotes(account, proposal.voteStart, params); _countVote(proposalId, account, support, weight, params); if (params.length == 0) { diff --git a/contracts/governance/IGovernor.sol b/contracts/governance/IGovernor.sol index 60a4b5470..b12d2f632 100644 --- a/contracts/governance/IGovernor.sol +++ b/contracts/governance/IGovernor.sol @@ -3,14 +3,15 @@ pragma solidity ^0.8.0; -import "../utils/introspection/ERC165.sol"; +import "../interfaces/IERC165.sol"; +import "../interfaces/IERC6372.sol"; /** * @dev Interface of the {Governor} core. * * _Available since v4.3._ */ -abstract contract IGovernor is IERC165 { +abstract contract IGovernor is IERC165, IERC6372 { enum ProposalState { Pending, Active, @@ -32,8 +33,8 @@ abstract contract IGovernor is IERC165 { uint256[] values, string[] signatures, bytes[] calldatas, - uint256 startBlock, - uint256 endBlock, + uint256 voteStart, + uint256 voteEnd, string description ); @@ -81,6 +82,19 @@ abstract contract IGovernor is IERC165 { */ function version() public view virtual returns (string memory); + /** + * @notice module:core + * @dev See {IERC6372} + */ + function clock() public view virtual override returns (uint48); + + /** + * @notice module:core + * @dev See EIP-6372. + */ + // solhint-disable-next-line func-name-mixedcase + function CLOCK_MODE() public view virtual override returns (string memory); + /** * @notice module:voting * @dev A description of the possible `support` values for {castVote} and the way these votes are counted, meant to @@ -104,7 +118,7 @@ abstract contract IGovernor is IERC165 { * JavaScript class. */ // solhint-disable-next-line func-name-mixedcase - function COUNTING_MODE() public pure virtual returns (string memory); + function COUNTING_MODE() public view virtual returns (string memory); /** * @notice module:core @@ -125,29 +139,33 @@ abstract contract IGovernor is IERC165 { /** * @notice module:core - * @dev Block number used to retrieve user's votes and quorum. As per Compound's Comp and OpenZeppelin's - * ERC20Votes, the snapshot is performed at the end of this block. Hence, voting for this proposal starts at the - * beginning of the following block. + * @dev Timepoint used to retrieve user's votes and quorum. If using block number (as per Compound's Comp), the + * snapshot is performed at the end of this block. Hence, voting for this proposal starts at the beginning of the + * following block. */ function proposalSnapshot(uint256 proposalId) public view virtual returns (uint256); /** * @notice module:core - * @dev Block number at which votes close. Votes close at the end of this block, so it is possible to cast a vote - * during this block. + * @dev Timepoint at which votes close. If using block number, votes close at the end of this block, so it is + * possible to cast a vote during this block. */ function proposalDeadline(uint256 proposalId) public view virtual returns (uint256); /** * @notice module:user-config - * @dev Delay, in number of block, between the proposal is created and the vote starts. This can be increased to - * leave time for users to buy voting power, or delegate it, before the voting of a proposal starts. + * @dev Delay, between the proposal is created and the vote starts. The unit this duration is expressed in depends + * on the clock (see EIP-6372) this contract uses. + * + * This can be increased to leave time for users to buy voting power, or delegate it, before the voting of a + * proposal starts. */ function votingDelay() public view virtual returns (uint256); /** * @notice module:user-config - * @dev Delay, in number of blocks, between the vote start and vote ends. + * @dev Delay, between the vote start and vote ends. The unit this duration is expressed in depends on the clock + * (see EIP-6372) this contract uses. * * NOTE: The {votingDelay} can delay the start of the vote. This must be considered when setting the voting * duration compared to the voting delay. @@ -158,27 +176,27 @@ abstract contract IGovernor is IERC165 { * @notice module:user-config * @dev Minimum number of cast voted required for a proposal to be successful. * - * Note: The `blockNumber` parameter corresponds to the snapshot used for counting vote. This allows to scale the - * quorum depending on values such as the totalSupply of a token at this block (see {ERC20Votes}). + * NOTE: The `timepoint` parameter corresponds to the snapshot used for counting vote. This allows to scale the + * quorum depending on values such as the totalSupply of a token at this timepoint (see {ERC20Votes}). */ - function quorum(uint256 blockNumber) public view virtual returns (uint256); + function quorum(uint256 timepoint) public view virtual returns (uint256); /** * @notice module:reputation - * @dev Voting power of an `account` at a specific `blockNumber`. + * @dev Voting power of an `account` at a specific `timepoint`. * * Note: this can be implemented in a number of ways, for example by reading the delegated balance from one (or * multiple), {ERC20Votes} tokens. */ - function getVotes(address account, uint256 blockNumber) public view virtual returns (uint256); + function getVotes(address account, uint256 timepoint) public view virtual returns (uint256); /** * @notice module:reputation - * @dev Voting power of an `account` at a specific `blockNumber` given additional encoded parameters. + * @dev Voting power of an `account` at a specific `timepoint` given additional encoded parameters. */ function getVotesWithParams( address account, - uint256 blockNumber, + uint256 timepoint, bytes memory params ) public view virtual returns (uint256); @@ -189,8 +207,8 @@ abstract contract IGovernor is IERC165 { function hasVoted(uint256 proposalId, address account) public view virtual returns (bool); /** - * @dev Create a new proposal. Vote start {IGovernor-votingDelay} blocks after the proposal is created and ends - * {IGovernor-votingPeriod} blocks after the voting starts. + * @dev Create a new proposal. Vote start after a delay specified by {IGovernor-votingDelay} and lasts for a + * duration specified by {IGovernor-votingPeriod}. * * Emits a {ProposalCreated} event. */ diff --git a/contracts/governance/README.adoc b/contracts/governance/README.adoc index 9bfa64fea..6d53e973d 100644 --- a/contracts/governance/README.adoc +++ b/contracts/governance/README.adoc @@ -46,9 +46,9 @@ Other extensions can customize the behavior or interface in multiple ways. In addition to modules and extensions, the core contract requires a few virtual functions to be implemented to your particular specifications: -* <>: Delay (in number of blocks) 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. -* <>: Delay (in number of blocks) since the proposal starts until voting ends. -* <>: Quorum required for a proposal to be successful. This function includes a `blockNumber` argument so the quorum can adapt through time, for example, to follow a token's `totalSupply`. +* <>: Delay (in EIP-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. +* <>: Delay (in EIP-6372 clock) since the proposal starts until voting ends. +* <>: Quorum required for a proposal to be successful. This function includes a `timepoint` argument (see EIP-6372) so the quorum can adapt through time, for example, to follow a token's `totalSupply`. NOTE: Functions of the `Governor` contract do not include access control. If you want to restrict access, you should add these checks by overloading the particular functions. Among these, {Governor-_cancel} is internal by default, and you will have to expose it (with the right access control mechanism) yourself if this function is needed. diff --git a/contracts/governance/compatibility/GovernorCompatibilityBravo.sol b/contracts/governance/compatibility/GovernorCompatibilityBravo.sol index 912d02f8a..1b8c09368 100644 --- a/contracts/governance/compatibility/GovernorCompatibilityBravo.sol +++ b/contracts/governance/compatibility/GovernorCompatibilityBravo.sol @@ -100,10 +100,10 @@ abstract contract GovernorCompatibilityBravo is IGovernorTimelock, IGovernorComp } function cancel(uint256 proposalId) public virtual override(IGovernor, Governor) { - ProposalDetails storage details = _proposalDetails[proposalId]; + address proposer = _proposalDetails[proposalId].proposer; require( - _msgSender() == details.proposer || getVotes(details.proposer, block.number - 1) < proposalThreshold(), + _msgSender() == proposer || getVotes(proposer, clock() - 1) < proposalThreshold(), "GovernorBravo: proposer above threshold" ); @@ -225,7 +225,7 @@ abstract contract GovernorCompatibilityBravo is IGovernorTimelock, IGovernorComp * @dev See {IGovernorCompatibilityBravo-quorumVotes}. */ function quorumVotes() public view virtual override returns (uint256) { - return quorum(block.number - 1); + return quorum(clock() - 1); } // ==================================================== Voting ==================================================== diff --git a/contracts/governance/extensions/GovernorPreventLateQuorum.sol b/contracts/governance/extensions/GovernorPreventLateQuorum.sol index a26bbf059..676d2b13e 100644 --- a/contracts/governance/extensions/GovernorPreventLateQuorum.sol +++ b/contracts/governance/extensions/GovernorPreventLateQuorum.sol @@ -19,10 +19,11 @@ import "../../utils/math/Math.sol"; */ abstract contract GovernorPreventLateQuorum is Governor { using SafeCast for uint256; - using Timers for Timers.BlockNumber; uint64 private _voteExtension; - mapping(uint256 => Timers.BlockNumber) private _extendedDeadlines; + + /// @custom:oz-retyped-from mapping(uint256 => Timers.BlockNumber) + mapping(uint256 => uint64) private _extendedDeadlines; /// @dev Emitted when a proposal deadline is pushed back due to reaching quorum late in its voting period. event ProposalExtended(uint256 indexed proposalId, uint64 extendedDeadline); @@ -44,7 +45,7 @@ abstract contract GovernorPreventLateQuorum is Governor { * proposal reached quorum late in the voting period. See {Governor-proposalDeadline}. */ function proposalDeadline(uint256 proposalId) public view virtual override returns (uint256) { - return Math.max(super.proposalDeadline(proposalId), _extendedDeadlines[proposalId].getDeadline()); + return Math.max(super.proposalDeadline(proposalId), _extendedDeadlines[proposalId]); } /** @@ -62,16 +63,14 @@ abstract contract GovernorPreventLateQuorum is Governor { ) internal virtual override returns (uint256) { uint256 result = super._castVote(proposalId, account, support, reason, params); - Timers.BlockNumber storage extendedDeadline = _extendedDeadlines[proposalId]; + if (_extendedDeadlines[proposalId] == 0 && _quorumReached(proposalId)) { + uint64 extendedDeadline = clock() + lateQuorumVoteExtension(); - if (extendedDeadline.isUnset() && _quorumReached(proposalId)) { - uint64 extendedDeadlineValue = block.number.toUint64() + lateQuorumVoteExtension(); - - if (extendedDeadlineValue > proposalDeadline(proposalId)) { - emit ProposalExtended(proposalId, extendedDeadlineValue); + if (extendedDeadline > proposalDeadline(proposalId)) { + emit ProposalExtended(proposalId, extendedDeadline); } - extendedDeadline.setDeadline(extendedDeadlineValue); + _extendedDeadlines[proposalId] = extendedDeadline; } return result; diff --git a/contracts/governance/extensions/GovernorTimelockCompound.sol b/contracts/governance/extensions/GovernorTimelockCompound.sol index 2fa539ead..629f8f800 100644 --- a/contracts/governance/extensions/GovernorTimelockCompound.sol +++ b/contracts/governance/extensions/GovernorTimelockCompound.sol @@ -22,15 +22,11 @@ import "../../vendor/compound/ICompoundTimelock.sol"; */ abstract contract GovernorTimelockCompound is IGovernorTimelock, Governor { using SafeCast for uint256; - using Timers for Timers.Timestamp; - - struct ProposalTimelock { - Timers.Timestamp timer; - } ICompoundTimelock private _timelock; - mapping(uint256 => ProposalTimelock) private _proposalTimelocks; + /// @custom:oz-retyped-from mapping(uint256 => GovernorTimelockCompound.ProposalTimelock) + mapping(uint256 => uint64) private _proposalTimelocks; /** * @dev Emitted when the timelock controller used for proposal execution is modified. @@ -82,7 +78,7 @@ abstract contract GovernorTimelockCompound is IGovernorTimelock, Governor { * @dev Public accessor to check the eta of a queued proposal */ function proposalEta(uint256 proposalId) public view virtual override returns (uint256) { - return _proposalTimelocks[proposalId].timer.getDeadline(); + return _proposalTimelocks[proposalId]; } /** @@ -99,7 +95,8 @@ abstract contract GovernorTimelockCompound is IGovernorTimelock, Governor { require(state(proposalId) == ProposalState.Succeeded, "Governor: proposal not successful"); uint256 eta = block.timestamp + _timelock.delay(); - _proposalTimelocks[proposalId].timer.setDeadline(eta.toUint64()); + _proposalTimelocks[proposalId] = eta.toUint64(); + for (uint256 i = 0; i < targets.length; ++i) { require( !_timelock.queuedTransactions(keccak256(abi.encode(targets[i], values[i], "", calldatas[i], eta))), @@ -145,10 +142,12 @@ abstract contract GovernorTimelockCompound is IGovernorTimelock, Governor { uint256 eta = proposalEta(proposalId); if (eta > 0) { + // update state first + delete _proposalTimelocks[proposalId]; + // do external call later for (uint256 i = 0; i < targets.length; ++i) { _timelock.cancelTransaction(targets[i], values[i], "", calldatas[i], eta); } - _proposalTimelocks[proposalId].timer.reset(); } return proposalId; diff --git a/contracts/governance/extensions/GovernorVotes.sol b/contracts/governance/extensions/GovernorVotes.sol index b328c25d1..644317111 100644 --- a/contracts/governance/extensions/GovernorVotes.sol +++ b/contracts/governance/extensions/GovernorVotes.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.0; import "../Governor.sol"; -import "../utils/IVotes.sol"; +import "../../interfaces/IERC5805.sol"; /** * @dev Extension of {Governor} for voting weight extraction from an {ERC20Votes} token, or since v4.5 an {ERC721Votes} token. @@ -12,10 +12,34 @@ import "../utils/IVotes.sol"; * _Available since v4.3._ */ abstract contract GovernorVotes is Governor { - IVotes public immutable token; + IERC5805 public immutable token; constructor(IVotes tokenAddress) { - token = tokenAddress; + token = IERC5805(address(tokenAddress)); + } + + /** + * @dev Clock (as specified in EIP-6372) is set to match the token's clock. Fallback to block numbers if the token + * does not implement EIP-6372. + */ + function clock() public view virtual override returns (uint48) { + try token.clock() returns (uint48 timepoint) { + return timepoint; + } catch { + return SafeCast.toUint48(block.number); + } + } + + /** + * @dev Machine-readable description of the clock as specified in EIP-6372. + */ + // solhint-disable-next-line func-name-mixedcase + function CLOCK_MODE() public view virtual override returns (string memory) { + try token.CLOCK_MODE() returns (string memory clockmode) { + return clockmode; + } catch { + return "mode=blocknumber&from=default"; + } } /** @@ -23,9 +47,9 @@ abstract contract GovernorVotes is Governor { */ function _getVotes( address account, - uint256 blockNumber, + uint256 timepoint, bytes memory /*params*/ ) internal view virtual override returns (uint256) { - return token.getPastVotes(account, blockNumber); + return token.getPastVotes(account, timepoint); } } diff --git a/contracts/governance/extensions/GovernorVotesComp.sol b/contracts/governance/extensions/GovernorVotesComp.sol index 8c4a1f8c1..17250ad7b 100644 --- a/contracts/governance/extensions/GovernorVotesComp.sol +++ b/contracts/governance/extensions/GovernorVotesComp.sol @@ -19,13 +19,37 @@ abstract contract GovernorVotesComp is Governor { } /** - * Read the voting weight from the token's built in snapshot mechanism (see {Governor-_getVotes}). + * @dev Clock (as specified in EIP-6372) is set to match the token's clock. Fallback to block numbers if the token + * does not implement EIP-6372. + */ + function clock() public view virtual override returns (uint48) { + try token.clock() returns (uint48 timepoint) { + return timepoint; + } catch { + return SafeCast.toUint48(block.number); + } + } + + /** + * @dev Machine-readable description of the clock as specified in EIP-6372. + */ + // solhint-disable-next-line func-name-mixedcase + function CLOCK_MODE() public view virtual override returns (string memory) { + try token.CLOCK_MODE() returns (string memory clockmode) { + return clockmode; + } catch { + return "mode=blocknumber&from=default"; + } + } + + /** + * Read the voting weight from the token's built-in snapshot mechanism (see {Governor-_getVotes}). */ function _getVotes( address account, - uint256 blockNumber, + uint256 timepoint, bytes memory /*params*/ ) internal view virtual override returns (uint256) { - return token.getPriorVotes(account, blockNumber); + return token.getPriorVotes(account, timepoint); } } diff --git a/contracts/governance/extensions/GovernorVotesQuorumFraction.sol b/contracts/governance/extensions/GovernorVotesQuorumFraction.sol index 8efefce39..19c5b194d 100644 --- a/contracts/governance/extensions/GovernorVotesQuorumFraction.sol +++ b/contracts/governance/extensions/GovernorVotesQuorumFraction.sol @@ -14,10 +14,13 @@ import "../../utils/math/SafeCast.sol"; * _Available since v4.3._ */ abstract contract GovernorVotesQuorumFraction is GovernorVotes { - using Checkpoints for Checkpoints.History; + using SafeCast for *; + using Checkpoints for Checkpoints.Trace224; - uint256 private _quorumNumerator; // DEPRECATED - Checkpoints.History private _quorumNumeratorHistory; + uint256 private _quorumNumerator; // DEPRECATED in favor of _quorumNumeratorHistory + + /// @custom:oz-retyped-from Checkpoints.History + Checkpoints.Trace224 private _quorumNumeratorHistory; event QuorumNumeratorUpdated(uint256 oldQuorumNumerator, uint256 newQuorumNumerator); @@ -40,9 +43,9 @@ abstract contract GovernorVotesQuorumFraction is GovernorVotes { } /** - * @dev Returns the quorum numerator at a specific block number. See {quorumDenominator}. + * @dev Returns the quorum numerator at a specific timepoint. See {quorumDenominator}. */ - function quorumNumerator(uint256 blockNumber) public view virtual returns (uint256) { + function quorumNumerator(uint256 timepoint) public view virtual returns (uint256) { // If history is empty, fallback to old storage uint256 length = _quorumNumeratorHistory._checkpoints.length; if (length == 0) { @@ -50,13 +53,13 @@ abstract contract GovernorVotesQuorumFraction is GovernorVotes { } // Optimistic search, check the latest checkpoint - Checkpoints.Checkpoint memory latest = _quorumNumeratorHistory._checkpoints[length - 1]; - if (latest._blockNumber <= blockNumber) { + Checkpoints.Checkpoint224 memory latest = _quorumNumeratorHistory._checkpoints[length - 1]; + if (latest._key <= timepoint) { return latest._value; } // Otherwise, do the binary search - return _quorumNumeratorHistory.getAtBlock(blockNumber); + return _quorumNumeratorHistory.upperLookupRecent(timepoint.toUint32()); } /** @@ -67,10 +70,10 @@ abstract contract GovernorVotesQuorumFraction is GovernorVotes { } /** - * @dev Returns the quorum for a block number, in terms of number of votes: `supply * numerator / denominator`. + * @dev Returns the quorum for a timepoint, in terms of number of votes: `supply * numerator / denominator`. */ - function quorum(uint256 blockNumber) public view virtual override returns (uint256) { - return (token.getPastTotalSupply(blockNumber) * quorumNumerator(blockNumber)) / quorumDenominator(); + function quorum(uint256 timepoint) public view virtual override returns (uint256) { + return (token.getPastTotalSupply(timepoint) * quorumNumerator(timepoint)) / quorumDenominator(); } /** @@ -107,12 +110,12 @@ abstract contract GovernorVotesQuorumFraction is GovernorVotes { // Make sure we keep track of the original numerator in contracts upgraded from a version without checkpoints. if (oldQuorumNumerator != 0 && _quorumNumeratorHistory._checkpoints.length == 0) { _quorumNumeratorHistory._checkpoints.push( - Checkpoints.Checkpoint({_blockNumber: 0, _value: SafeCast.toUint224(oldQuorumNumerator)}) + Checkpoints.Checkpoint224({_key: 0, _value: oldQuorumNumerator.toUint224()}) ); } // Set new quorum for future proposals - _quorumNumeratorHistory.push(newQuorumNumerator); + _quorumNumeratorHistory.push(clock().toUint32(), newQuorumNumerator.toUint224()); emit QuorumNumeratorUpdated(oldQuorumNumerator, newQuorumNumerator); } diff --git a/contracts/governance/utils/IVotes.sol b/contracts/governance/utils/IVotes.sol index 0bef3f920..c73d0732b 100644 --- a/contracts/governance/utils/IVotes.sol +++ b/contracts/governance/utils/IVotes.sol @@ -24,18 +24,20 @@ interface IVotes { function getVotes(address account) external view returns (uint256); /** - * @dev Returns the amount of votes that `account` had at the end of a past block (`blockNumber`). + * @dev Returns the amount of votes that `account` had at a specific moment in the past. If the `clock()` is + * configured to use block numbers, this will return the value the end of the corresponding block. */ - function getPastVotes(address account, uint256 blockNumber) external view returns (uint256); + function getPastVotes(address account, uint256 timepoint) external view returns (uint256); /** - * @dev Returns the total supply of votes available at the end of a past block (`blockNumber`). + * @dev Returns the total supply of votes available at a specific moment in the past. If the `clock()` is + * configured to use block numbers, this will return the value the end of the corresponding block. * * NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes. * Votes that have not been delegated are still part of total supply, even though they would not participate in a * vote. */ - function getPastTotalSupply(uint256 blockNumber) external view returns (uint256); + function getPastTotalSupply(uint256 timepoint) external view returns (uint256); /** * @dev Returns the delegate that `account` has chosen. diff --git a/contracts/governance/utils/Votes.sol b/contracts/governance/utils/Votes.sol index 2eecf32c6..f70cf3831 100644 --- a/contracts/governance/utils/Votes.sol +++ b/contracts/governance/utils/Votes.sol @@ -2,11 +2,11 @@ // OpenZeppelin Contracts (last updated v4.8.0) (governance/utils/Votes.sol) pragma solidity ^0.8.0; +import "../../interfaces/IERC5805.sol"; import "../../utils/Context.sol"; import "../../utils/Counters.sol"; import "../../utils/Checkpoints.sol"; import "../../utils/cryptography/EIP712.sol"; -import "./IVotes.sol"; /** * @dev This is a base abstract contract that tracks voting units, which are a measure of voting power that can be @@ -28,19 +28,41 @@ import "./IVotes.sol"; * * _Available since v4.5._ */ -abstract contract Votes is IVotes, Context, EIP712 { - using Checkpoints for Checkpoints.History; +abstract contract Votes is Context, EIP712, IERC5805 { + using Checkpoints for Checkpoints.Trace224; using Counters for Counters.Counter; bytes32 private constant _DELEGATION_TYPEHASH = keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)"); mapping(address => address) private _delegation; - mapping(address => Checkpoints.History) private _delegateCheckpoints; - Checkpoints.History private _totalCheckpoints; + + /// @custom:oz-retyped-from mapping(address => Checkpoints.History) + mapping(address => Checkpoints.Trace224) private _delegateCheckpoints; + + /// @custom:oz-retyped-from Checkpoints.History + Checkpoints.Trace224 private _totalCheckpoints; mapping(address => Counters.Counter) private _nonces; + /** + * @dev Clock used for flagging checkpoints. Can be overridden to implement timestamp based + * checkpoints (and voting), in which case {CLOCK_MODE} should be overridden as well to match. + */ + function clock() public view virtual override returns (uint48) { + return SafeCast.toUint48(block.number); + } + + /** + * @dev Machine-readable description of the clock as specified in EIP-6372. + */ + // solhint-disable-next-line func-name-mixedcase + function CLOCK_MODE() public view virtual override returns (string memory) { + // Check that the clock was not modified + require(clock() == block.number); + return "mode=blocknumber&from=default"; + } + /** * @dev Returns the current amount of votes that `account` has. */ @@ -49,18 +71,21 @@ abstract contract Votes is IVotes, Context, EIP712 { } /** - * @dev Returns the amount of votes that `account` had at the end of a past block (`blockNumber`). + * @dev Returns the amount of votes that `account` had at a specific moment in the past. If the `clock()` is + * configured to use block numbers, this will return the value the end of the corresponding block. * * Requirements: * - * - `blockNumber` must have been already mined + * - `timepoint` must be in the past. If operating using block numbers, the block must be already mined. */ - function getPastVotes(address account, uint256 blockNumber) public view virtual override returns (uint256) { - return _delegateCheckpoints[account].getAtProbablyRecentBlock(blockNumber); + function getPastVotes(address account, uint256 timepoint) public view virtual override returns (uint256) { + require(timepoint < clock(), "Votes: future lookup"); + return _delegateCheckpoints[account].upperLookupRecent(SafeCast.toUint32(timepoint)); } /** - * @dev Returns the total supply of votes available at the end of a past block (`blockNumber`). + * @dev Returns the total supply of votes available at a specific moment in the past. If the `clock()` is + * configured to use block numbers, this will return the value the end of the corresponding block. * * NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes. * Votes that have not been delegated are still part of total supply, even though they would not participate in a @@ -68,11 +93,11 @@ abstract contract Votes is IVotes, Context, EIP712 { * * Requirements: * - * - `blockNumber` must have been already mined + * - `timepoint` must be in the past. If operating using block numbers, the block must be already mined. */ - function getPastTotalSupply(uint256 blockNumber) public view virtual override returns (uint256) { - require(blockNumber < block.number, "Votes: block not yet mined"); - return _totalCheckpoints.getAtProbablyRecentBlock(blockNumber); + function getPastTotalSupply(uint256 timepoint) public view virtual override returns (uint256) { + require(timepoint < clock(), "Votes: future lookup"); + return _totalCheckpoints.upperLookupRecent(SafeCast.toUint32(timepoint)); } /** @@ -138,10 +163,10 @@ abstract contract Votes is IVotes, Context, EIP712 { */ function _transferVotingUnits(address from, address to, uint256 amount) internal virtual { if (from == address(0)) { - _totalCheckpoints.push(_add, amount); + _push(_totalCheckpoints, _add, SafeCast.toUint224(amount)); } if (to == address(0)) { - _totalCheckpoints.push(_subtract, amount); + _push(_totalCheckpoints, _subtract, SafeCast.toUint224(amount)); } _moveDelegateVotes(delegates(from), delegates(to), amount); } @@ -152,21 +177,37 @@ abstract contract Votes is IVotes, Context, EIP712 { function _moveDelegateVotes(address from, address to, uint256 amount) private { if (from != to && amount > 0) { if (from != address(0)) { - (uint256 oldValue, uint256 newValue) = _delegateCheckpoints[from].push(_subtract, amount); + (uint256 oldValue, uint256 newValue) = _push( + _delegateCheckpoints[from], + _subtract, + SafeCast.toUint224(amount) + ); emit DelegateVotesChanged(from, oldValue, newValue); } if (to != address(0)) { - (uint256 oldValue, uint256 newValue) = _delegateCheckpoints[to].push(_add, amount); + (uint256 oldValue, uint256 newValue) = _push( + _delegateCheckpoints[to], + _add, + SafeCast.toUint224(amount) + ); emit DelegateVotesChanged(to, oldValue, newValue); } } } - function _add(uint256 a, uint256 b) private pure returns (uint256) { + function _push( + Checkpoints.Trace224 storage store, + function(uint224, uint224) view returns (uint224) op, + uint224 delta + ) private returns (uint224, uint224) { + return store.push(SafeCast.toUint32(clock()), op(store.latest(), delta)); + } + + function _add(uint224 a, uint224 b) private pure returns (uint224) { return a + b; } - function _subtract(uint256 a, uint256 b) private pure returns (uint256) { + function _subtract(uint224 a, uint224 b) private pure returns (uint224) { return a - b; } diff --git a/contracts/interfaces/IERC5805.sol b/contracts/interfaces/IERC5805.sol new file mode 100644 index 000000000..2c2e5e345 --- /dev/null +++ b/contracts/interfaces/IERC5805.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (interfaces/IERC5805.sol) + +pragma solidity ^0.8.0; + +import "../governance/utils/IVotes.sol"; +import "./IERC6372.sol"; + +interface IERC5805 is IERC6372, IVotes {} diff --git a/contracts/interfaces/IERC6372.sol b/contracts/interfaces/IERC6372.sol new file mode 100644 index 000000000..e1a0bf8b0 --- /dev/null +++ b/contracts/interfaces/IERC6372.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (interfaces/IERC6372.sol) + +pragma solidity ^0.8.0; + +interface IERC6372 { + /** + * @dev Clock used for flagging checkpoints. Can be overridden to implement timestamp based checkpoints (and voting). + */ + function clock() external view returns (uint48); + + /** + * @dev Description of the clock + */ + // solhint-disable-next-line func-name-mixedcase + function CLOCK_MODE() external view returns (string memory); +} diff --git a/contracts/mocks/VotesMock.sol b/contracts/mocks/VotesMock.sol index ece08b075..829504e3a 100644 --- a/contracts/mocks/VotesMock.sol +++ b/contracts/mocks/VotesMock.sol @@ -32,3 +32,14 @@ abstract contract VotesMock is Votes { _transferVotingUnits(owner, address(0), 1); } } + +abstract contract VotesTimestampMock is VotesMock { + function clock() public view override returns (uint48) { + return uint48(block.timestamp); + } + + // solhint-disable-next-line func-name-mixedcase + function CLOCK_MODE() public view virtual override returns (string memory) { + return "mode=timestamp"; + } +} diff --git a/contracts/mocks/token/ERC20VotesLegacyMock.sol b/contracts/mocks/token/ERC20VotesLegacyMock.sol new file mode 100644 index 000000000..09a2675d9 --- /dev/null +++ b/contracts/mocks/token/ERC20VotesLegacyMock.sol @@ -0,0 +1,262 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../token/ERC20/extensions/ERC20Permit.sol"; +import "../../utils/math/Math.sol"; +import "../../governance/utils/IVotes.sol"; +import "../../utils/math/SafeCast.sol"; +import "../../utils/cryptography/ECDSA.sol"; + +/** + * @dev Copied from the master branch at commit 86de1e8b6c3fa6b4efa4a5435869d2521be0f5f5 + */ +abstract contract ERC20VotesLegacyMock is IVotes, ERC20Permit { + struct Checkpoint { + uint32 fromBlock; + uint224 votes; + } + + bytes32 private constant _DELEGATION_TYPEHASH = + keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)"); + + mapping(address => address) private _delegates; + mapping(address => Checkpoint[]) private _checkpoints; + Checkpoint[] private _totalSupplyCheckpoints; + + /** + * @dev Get the `pos`-th checkpoint for `account`. + */ + function checkpoints(address account, uint32 pos) public view virtual returns (Checkpoint memory) { + return _checkpoints[account][pos]; + } + + /** + * @dev Get number of checkpoints for `account`. + */ + function numCheckpoints(address account) public view virtual returns (uint32) { + return SafeCast.toUint32(_checkpoints[account].length); + } + + /** + * @dev Get the address `account` is currently delegating to. + */ + function delegates(address account) public view virtual override returns (address) { + return _delegates[account]; + } + + /** + * @dev Gets the current votes balance for `account` + */ + function getVotes(address account) public view virtual override returns (uint256) { + uint256 pos = _checkpoints[account].length; + unchecked { + return pos == 0 ? 0 : _checkpoints[account][pos - 1].votes; + } + } + + /** + * @dev Retrieve the number of votes for `account` at the end of `blockNumber`. + * + * Requirements: + * + * - `blockNumber` must have been already mined + */ + function getPastVotes(address account, uint256 blockNumber) public view virtual override returns (uint256) { + require(blockNumber < block.number, "ERC20Votes: block not yet mined"); + return _checkpointsLookup(_checkpoints[account], blockNumber); + } + + /** + * @dev Retrieve the `totalSupply` at the end of `blockNumber`. Note, this value is the sum of all balances. + * It is NOT the sum of all the delegated votes! + * + * Requirements: + * + * - `blockNumber` must have been already mined + */ + function getPastTotalSupply(uint256 blockNumber) public view virtual override returns (uint256) { + require(blockNumber < block.number, "ERC20Votes: block not yet mined"); + return _checkpointsLookup(_totalSupplyCheckpoints, blockNumber); + } + + /** + * @dev Lookup a value in a list of (sorted) checkpoints. + */ + function _checkpointsLookup(Checkpoint[] storage ckpts, uint256 blockNumber) private view returns (uint256) { + // We run a binary search to look for the earliest checkpoint taken after `blockNumber`. + // + // Initially we check if the block is recent to narrow the search range. + // During the loop, the index of the wanted checkpoint remains in the range [low-1, high). + // With each iteration, either `low` or `high` is moved towards the middle of the range to maintain the invariant. + // - If the middle checkpoint is after `blockNumber`, we look in [low, mid) + // - If the middle checkpoint is before or equal to `blockNumber`, we look in [mid+1, high) + // Once we reach a single value (when low == high), we've found the right checkpoint at the index high-1, if not + // out of bounds (in which case we're looking too far in the past and the result is 0). + // Note that if the latest checkpoint available is exactly for `blockNumber`, we end up with an index that is + // past the end of the array, so we technically don't find a checkpoint after `blockNumber`, but it works out + // the same. + uint256 length = ckpts.length; + + uint256 low = 0; + uint256 high = length; + + if (length > 5) { + uint256 mid = length - Math.sqrt(length); + if (_unsafeAccess(ckpts, mid).fromBlock > blockNumber) { + high = mid; + } else { + low = mid + 1; + } + } + + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(ckpts, mid).fromBlock > blockNumber) { + high = mid; + } else { + low = mid + 1; + } + } + + unchecked { + return high == 0 ? 0 : _unsafeAccess(ckpts, high - 1).votes; + } + } + + /** + * @dev Delegate votes from the sender to `delegatee`. + */ + function delegate(address delegatee) public virtual override { + _delegate(_msgSender(), delegatee); + } + + /** + * @dev Delegates votes from signer to `delegatee` + */ + function delegateBySig( + address delegatee, + uint256 nonce, + uint256 expiry, + uint8 v, + bytes32 r, + bytes32 s + ) public virtual override { + require(block.timestamp <= expiry, "ERC20Votes: signature expired"); + address signer = ECDSA.recover( + _hashTypedDataV4(keccak256(abi.encode(_DELEGATION_TYPEHASH, delegatee, nonce, expiry))), + v, + r, + s + ); + require(nonce == _useNonce(signer), "ERC20Votes: invalid nonce"); + _delegate(signer, delegatee); + } + + /** + * @dev Maximum token supply. Defaults to `type(uint224).max` (2^224^ - 1). + */ + function _maxSupply() internal view virtual returns (uint224) { + return type(uint224).max; + } + + /** + * @dev Snapshots the totalSupply after it has been increased. + */ + function _mint(address account, uint256 amount) internal virtual override { + super._mint(account, amount); + require(totalSupply() <= _maxSupply(), "ERC20Votes: total supply risks overflowing votes"); + + _writeCheckpoint(_totalSupplyCheckpoints, _add, amount); + } + + /** + * @dev Snapshots the totalSupply after it has been decreased. + */ + function _burn(address account, uint256 amount) internal virtual override { + super._burn(account, amount); + + _writeCheckpoint(_totalSupplyCheckpoints, _subtract, amount); + } + + /** + * @dev Move voting power when tokens are transferred. + * + * Emits a {IVotes-DelegateVotesChanged} event. + */ + function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual override { + super._afterTokenTransfer(from, to, amount); + + _moveVotingPower(delegates(from), delegates(to), amount); + } + + /** + * @dev Change delegation for `delegator` to `delegatee`. + * + * Emits events {IVotes-DelegateChanged} and {IVotes-DelegateVotesChanged}. + */ + function _delegate(address delegator, address delegatee) internal virtual { + address currentDelegate = delegates(delegator); + uint256 delegatorBalance = balanceOf(delegator); + _delegates[delegator] = delegatee; + + emit DelegateChanged(delegator, currentDelegate, delegatee); + + _moveVotingPower(currentDelegate, delegatee, delegatorBalance); + } + + function _moveVotingPower(address src, address dst, uint256 amount) private { + if (src != dst && amount > 0) { + if (src != address(0)) { + (uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[src], _subtract, amount); + emit DelegateVotesChanged(src, oldWeight, newWeight); + } + + if (dst != address(0)) { + (uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[dst], _add, amount); + emit DelegateVotesChanged(dst, oldWeight, newWeight); + } + } + } + + function _writeCheckpoint( + Checkpoint[] storage ckpts, + function(uint256, uint256) view returns (uint256) op, + uint256 delta + ) private returns (uint256 oldWeight, uint256 newWeight) { + uint256 pos = ckpts.length; + + unchecked { + Checkpoint memory oldCkpt = pos == 0 ? Checkpoint(0, 0) : _unsafeAccess(ckpts, pos - 1); + + oldWeight = oldCkpt.votes; + newWeight = op(oldWeight, delta); + + if (pos > 0 && oldCkpt.fromBlock == block.number) { + _unsafeAccess(ckpts, pos - 1).votes = SafeCast.toUint224(newWeight); + } else { + ckpts.push( + Checkpoint({fromBlock: SafeCast.toUint32(block.number), votes: SafeCast.toUint224(newWeight)}) + ); + } + } + } + + function _add(uint256 a, uint256 b) private pure returns (uint256) { + return a + b; + } + + function _subtract(uint256 a, uint256 b) private pure returns (uint256) { + return a - b; + } + + /** + * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. + */ + function _unsafeAccess(Checkpoint[] storage ckpts, uint256 pos) private pure returns (Checkpoint storage result) { + assembly { + mstore(0, ckpts.slot) + result.slot := add(keccak256(0, 0x20), pos) + } + } +} diff --git a/contracts/mocks/token/VotesTimestamp.sol b/contracts/mocks/token/VotesTimestamp.sol new file mode 100644 index 000000000..179c500f4 --- /dev/null +++ b/contracts/mocks/token/VotesTimestamp.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../token/ERC20/extensions/ERC20Votes.sol"; +import "../../token/ERC20/extensions/ERC20VotesComp.sol"; +import "../../token/ERC721/extensions/ERC721Votes.sol"; + +abstract contract ERC20VotesTimestampMock is ERC20Votes { + function clock() public view virtual override returns (uint48) { + return SafeCast.toUint48(block.timestamp); + } + + // solhint-disable-next-line func-name-mixedcase + function CLOCK_MODE() public view virtual override returns (string memory) { + return "mode=timestamp"; + } +} + +abstract contract ERC20VotesCompTimestampMock is ERC20VotesComp { + function clock() public view virtual override returns (uint48) { + return SafeCast.toUint48(block.timestamp); + } + + // solhint-disable-next-line func-name-mixedcase + function CLOCK_MODE() public view virtual override returns (string memory) { + return "mode=timestamp"; + } +} + +abstract contract ERC721VotesTimestampMock is ERC721Votes { + function clock() public view virtual override returns (uint48) { + return SafeCast.toUint48(block.timestamp); + } + + // solhint-disable-next-line func-name-mixedcase + function CLOCK_MODE() public view virtual override returns (string memory) { + return "mode=timestamp"; + } +} diff --git a/contracts/token/ERC20/extensions/ERC20Votes.sol b/contracts/token/ERC20/extensions/ERC20Votes.sol index bf1c2fd5d..273bb8c50 100644 --- a/contracts/token/ERC20/extensions/ERC20Votes.sol +++ b/contracts/token/ERC20/extensions/ERC20Votes.sol @@ -4,8 +4,8 @@ pragma solidity ^0.8.0; import "./ERC20Permit.sol"; +import "../../../interfaces/IERC5805.sol"; import "../../../utils/math/Math.sol"; -import "../../../governance/utils/IVotes.sol"; import "../../../utils/math/SafeCast.sol"; import "../../../utils/cryptography/ECDSA.sol"; @@ -24,7 +24,7 @@ import "../../../utils/cryptography/ECDSA.sol"; * * _Available since v4.2._ */ -abstract contract ERC20Votes is IVotes, ERC20Permit { +abstract contract ERC20Votes is ERC20Permit, IERC5805 { struct Checkpoint { uint32 fromBlock; uint224 votes; @@ -37,6 +37,23 @@ abstract contract ERC20Votes is IVotes, ERC20Permit { mapping(address => Checkpoint[]) private _checkpoints; Checkpoint[] private _totalSupplyCheckpoints; + /** + * @dev Clock used for flagging checkpoints. Can be overridden to implement timestamp based checkpoints (and voting). + */ + function clock() public view virtual override returns (uint48) { + return SafeCast.toUint48(block.number); + } + + /** + * @dev Description of the clock + */ + // solhint-disable-next-line func-name-mixedcase + function CLOCK_MODE() public view virtual override returns (string memory) { + // Check that the clock was not modified + require(clock() == block.number); + return "mode=blocknumber&from=default"; + } + /** * @dev Get the `pos`-th checkpoint for `account`. */ @@ -69,45 +86,45 @@ abstract contract ERC20Votes is IVotes, ERC20Permit { } /** - * @dev Retrieve the number of votes for `account` at the end of `blockNumber`. + * @dev Retrieve the number of votes for `account` at the end of `timepoint`. * * Requirements: * - * - `blockNumber` must have been already mined + * - `timepoint` must be in the past */ - function getPastVotes(address account, uint256 blockNumber) public view virtual override returns (uint256) { - require(blockNumber < block.number, "ERC20Votes: block not yet mined"); - return _checkpointsLookup(_checkpoints[account], blockNumber); + function getPastVotes(address account, uint256 timepoint) public view virtual override returns (uint256) { + require(timepoint < clock(), "ERC20Votes: future lookup"); + return _checkpointsLookup(_checkpoints[account], timepoint); } /** - * @dev Retrieve the `totalSupply` at the end of `blockNumber`. Note, this value is the sum of all balances. + * @dev Retrieve the `totalSupply` at the end of `timepoint`. Note, this value is the sum of all balances. * It is NOT the sum of all the delegated votes! * * Requirements: * - * - `blockNumber` must have been already mined + * - `timepoint` must be in the past */ - function getPastTotalSupply(uint256 blockNumber) public view virtual override returns (uint256) { - require(blockNumber < block.number, "ERC20Votes: block not yet mined"); - return _checkpointsLookup(_totalSupplyCheckpoints, blockNumber); + function getPastTotalSupply(uint256 timepoint) public view virtual override returns (uint256) { + require(timepoint < clock(), "ERC20Votes: future lookup"); + return _checkpointsLookup(_totalSupplyCheckpoints, timepoint); } /** * @dev Lookup a value in a list of (sorted) checkpoints. */ - function _checkpointsLookup(Checkpoint[] storage ckpts, uint256 blockNumber) private view returns (uint256) { - // We run a binary search to look for the earliest checkpoint taken after `blockNumber`. + function _checkpointsLookup(Checkpoint[] storage ckpts, uint256 timepoint) private view returns (uint256) { + // We run a binary search to look for the earliest checkpoint taken after `timepoint`. // // Initially we check if the block is recent to narrow the search range. // During the loop, the index of the wanted checkpoint remains in the range [low-1, high). // With each iteration, either `low` or `high` is moved towards the middle of the range to maintain the invariant. - // - If the middle checkpoint is after `blockNumber`, we look in [low, mid) - // - If the middle checkpoint is before or equal to `blockNumber`, we look in [mid+1, high) + // - If the middle checkpoint is after `timepoint`, we look in [low, mid) + // - If the middle checkpoint is before or equal to `timepoint`, we look in [mid+1, high) // Once we reach a single value (when low == high), we've found the right checkpoint at the index high-1, if not // out of bounds (in which case we're looking too far in the past and the result is 0). - // Note that if the latest checkpoint available is exactly for `blockNumber`, we end up with an index that is - // past the end of the array, so we technically don't find a checkpoint after `blockNumber`, but it works out + // Note that if the latest checkpoint available is exactly for `timepoint`, we end up with an index that is + // past the end of the array, so we technically don't find a checkpoint after `timepoint`, but it works out // the same. uint256 length = ckpts.length; @@ -116,7 +133,7 @@ abstract contract ERC20Votes is IVotes, ERC20Permit { if (length > 5) { uint256 mid = length - Math.sqrt(length); - if (_unsafeAccess(ckpts, mid).fromBlock > blockNumber) { + if (_unsafeAccess(ckpts, mid).fromBlock > timepoint) { high = mid; } else { low = mid + 1; @@ -125,7 +142,7 @@ abstract contract ERC20Votes is IVotes, ERC20Permit { while (low < high) { uint256 mid = Math.average(low, high); - if (_unsafeAccess(ckpts, mid).fromBlock > blockNumber) { + if (_unsafeAccess(ckpts, mid).fromBlock > timepoint) { high = mid; } else { low = mid + 1; @@ -245,12 +262,10 @@ abstract contract ERC20Votes is IVotes, ERC20Permit { oldWeight = oldCkpt.votes; newWeight = op(oldWeight, delta); - if (pos > 0 && oldCkpt.fromBlock == block.number) { + if (pos > 0 && oldCkpt.fromBlock == clock()) { _unsafeAccess(ckpts, pos - 1).votes = SafeCast.toUint224(newWeight); } else { - ckpts.push( - Checkpoint({fromBlock: SafeCast.toUint32(block.number), votes: SafeCast.toUint224(newWeight)}) - ); + ckpts.push(Checkpoint({fromBlock: SafeCast.toUint32(clock()), votes: SafeCast.toUint224(newWeight)})); } } } diff --git a/contracts/utils/Checkpoints.sol b/contracts/utils/Checkpoints.sol index 0e0a136a0..025b13d0a 100644 --- a/contracts/utils/Checkpoints.sol +++ b/contracts/utils/Checkpoints.sol @@ -242,6 +242,31 @@ library Checkpoints { return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; } + /** + * @dev Returns the value in the most recent checkpoint with key lower or equal than the search key. + * + * NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high keys). + */ + function upperLookupRecent(Trace224 storage self, uint32 key) internal view returns (uint224) { + uint256 len = self._checkpoints.length; + + uint256 low = 0; + uint256 high = len; + + if (len > 5) { + uint256 mid = len - Math.sqrt(len); + if (key < _unsafeAccess(self._checkpoints, mid)._key) { + high = mid; + } else { + low = mid + 1; + } + } + + uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high); + + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + /** * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints. */ @@ -393,6 +418,31 @@ library Checkpoints { return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; } + /** + * @dev Returns the value in the most recent checkpoint with key lower or equal than the search key. + * + * NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high keys). + */ + function upperLookupRecent(Trace160 storage self, uint96 key) internal view returns (uint160) { + uint256 len = self._checkpoints.length; + + uint256 low = 0; + uint256 high = len; + + if (len > 5) { + uint256 mid = len - Math.sqrt(len); + if (key < _unsafeAccess(self._checkpoints, mid)._key) { + high = mid; + } else { + low = mid + 1; + } + } + + uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high); + + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + /** * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints. */ diff --git a/scripts/checks/compare-layout.js b/scripts/checks/compare-layout.js index ff8cb712e..7b7df9928 100644 --- a/scripts/checks/compare-layout.js +++ b/scripts/checks/compare-layout.js @@ -10,7 +10,6 @@ for (const name in oldLayout) { if (name in newLayout) { const report = getStorageUpgradeReport(oldLayout[name], newLayout[name], {}); if (!report.ok) { - console.log(`ERROR: Storage incompatibility in ${name}`); console.log(report.explain()); process.exitCode = 1; } diff --git a/scripts/checks/compareGasReports.js b/scripts/checks/compareGasReports.js index ca99dea0d..160c8cc52 100755 --- a/scripts/checks/compareGasReports.js +++ b/scripts/checks/compareGasReports.js @@ -10,6 +10,14 @@ const { argv } = require('yargs') choices: ['shell', 'markdown'], default: 'shell', }, + hideEqual: { + type: 'boolean', + default: true, + }, + strictTesting: { + type: 'boolean', + default: false, + }, }); // Deduce base tx cost from the percentage denominator @@ -40,7 +48,7 @@ class Report { } // Compare two reports - static compare(update, ref, opts = { hideEqual: true }) { + static compare(update, ref, opts = { hideEqual: true, strictTesting: false }) { if (JSON.stringify(update.config.metadata) !== JSON.stringify(ref.config.metadata)) { throw new Error('Reports produced with non matching metadata'); } @@ -70,7 +78,9 @@ class Report { const methods = Object.keys(update.info.methods) .filter(key => ref.info.methods[key]) .filter(key => update.info.methods[key].numberOfCalls > 0) - .filter(key => update.info.methods[key].numberOfCalls === ref.info.methods[key].numberOfCalls) + .filter( + key => !opts.strictTesting || update.info.methods[key].numberOfCalls === ref.info.methods[key].numberOfCalls, + ) .map(key => ({ contract: ref.info.methods[key].contract, method: ref.info.methods[key].fnSig, @@ -220,7 +230,7 @@ function formatCmpMarkdown(rows) { } // MAIN -const report = Report.compare(Report.load(argv._[0]), Report.load(argv._[1])); +const report = Report.compare(Report.load(argv._[0]), Report.load(argv._[1]), argv); switch (argv.style) { case 'markdown': diff --git a/scripts/generate/templates/Checkpoints.js b/scripts/generate/templates/Checkpoints.js index afac25991..e51e8b8d1 100644 --- a/scripts/generate/templates/Checkpoints.js +++ b/scripts/generate/templates/Checkpoints.js @@ -1,7 +1,28 @@ const format = require('../format-lines'); +// OPTIONS +const defaultOpts = size => ({ + historyTypeName: `Trace${size}`, + checkpointTypeName: `Checkpoint${size}`, + checkpointFieldName: '_checkpoints', + keyTypeName: `uint${256 - size}`, + keyFieldName: '_key', + valueTypeName: `uint${size}`, + valueFieldName: '_value', +}); + const VALUE_SIZES = [224, 160]; +const OPTS = VALUE_SIZES.map(size => defaultOpts(size)); + +const LEGACY_OPTS = { + ...defaultOpts(224), + historyTypeName: 'History', + checkpointTypeName: 'Checkpoint', + keyFieldName: '_blockNumber', +}; + +// TEMPLATE const header = `\ pragma solidity ^0.8.0; @@ -62,6 +83,31 @@ function upperLookup(${opts.historyTypeName} storage self, ${opts.keyTypeName} k uint256 pos = _upperBinaryLookup(self.${opts.checkpointFieldName}, key, 0, len); return pos == 0 ? 0 : _unsafeAccess(self.${opts.checkpointFieldName}, pos - 1).${opts.valueFieldName}; } + +/** + * @dev Returns the value in the most recent checkpoint with key lower or equal than the search key. + * + * NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high keys). + */ +function upperLookupRecent(${opts.historyTypeName} storage self, ${opts.keyTypeName} key) internal view returns (${opts.valueTypeName}) { + uint256 len = self.${opts.checkpointFieldName}.length; + + uint256 low = 0; + uint256 high = len; + + if (len > 5) { + uint256 mid = len - Math.sqrt(len); + if (key < _unsafeAccess(self.${opts.checkpointFieldName}, mid)._key) { + high = mid; + } else { + low = mid + 1; + } + } + + uint256 pos = _upperBinaryLookup(self.${opts.checkpointFieldName}, key, low, high); + + return pos == 0 ? 0 : _unsafeAccess(self.${opts.checkpointFieldName}, pos - 1).${opts.valueFieldName}; +} `; const legacyOperations = opts => `\ @@ -263,26 +309,6 @@ function _unsafeAccess(${opts.checkpointTypeName}[] storage self, uint256 pos) `; /* eslint-enable max-len */ -// OPTIONS -const defaultOpts = size => ({ - historyTypeName: `Trace${size}`, - checkpointTypeName: `Checkpoint${size}`, - checkpointFieldName: '_checkpoints', - keyTypeName: `uint${256 - size}`, - keyFieldName: '_key', - valueTypeName: `uint${size}`, - valueFieldName: '_value', -}); - -const OPTS = VALUE_SIZES.map(size => defaultOpts(size)); - -const LEGACY_OPTS = { - ...defaultOpts(224), - historyTypeName: 'History', - checkpointTypeName: 'Checkpoint', - keyFieldName: '_blockNumber', -}; - // GENERATE module.exports = format( header.trimEnd(), diff --git a/test/governance/Governor.test.js b/test/governance/Governor.test.js index 201895934..1eabaccf0 100644 --- a/test/governance/Governor.test.js +++ b/test/governance/Governor.test.js @@ -1,4 +1,4 @@ -const { BN, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); const { expect } = require('chai'); const ethSigUtil = require('eth-sig-util'); const Wallet = require('ethereumjs-wallet').default; @@ -6,676 +6,694 @@ const { fromRpcSig } = require('ethereumjs-util'); const Enums = require('../helpers/enums'); const { getDomain, domainType } = require('../helpers/eip712'); const { GovernorHelper } = require('../helpers/governance'); +const { clockFromReceipt } = require('../helpers/time'); const { shouldSupportInterfaces } = require('../utils/introspection/SupportsInterface.behavior'); +const { shouldBehaveLikeEIP6372 } = require('./utils/EIP6372.behavior'); -const Token = artifacts.require('$ERC20Votes'); const Governor = artifacts.require('$GovernorMock'); const CallReceiver = artifacts.require('CallReceiverMock'); const ERC721 = artifacts.require('$ERC721'); const ERC1155 = artifacts.require('$ERC1155'); +const TOKENS = [ + { Token: artifacts.require('$ERC20Votes'), mode: 'blocknumber' }, + { Token: artifacts.require('$ERC20VotesTimestampMock'), mode: 'timestamp' }, + { Token: artifacts.require('$ERC20VotesLegacyMock'), mode: 'blocknumber' }, +]; + contract('Governor', function (accounts) { const [owner, proposer, voter1, voter2, voter3, voter4] = accounts; - const empty = web3.utils.toChecksumAddress(web3.utils.randomHex(20)); const name = 'OZ-Governor'; const tokenName = 'MockToken'; const tokenSymbol = 'MTKN'; const tokenSupply = web3.utils.toWei('100'); - const votingDelay = new BN(4); - const votingPeriod = new BN(16); + const votingDelay = web3.utils.toBN(4); + const votingPeriod = web3.utils.toBN(16); const value = web3.utils.toWei('1'); - beforeEach(async function () { - this.chainId = await web3.eth.getChainId(); - this.token = await Token.new(tokenName, tokenSymbol, tokenName); - this.mock = await Governor.new( - name, // name - votingDelay, // initialVotingDelay - votingPeriod, // initialVotingPeriod - 0, // initialProposalThreshold - this.token.address, // tokenAddress - 10, // quorumNumeratorValue - ); - this.receiver = await CallReceiver.new(); + for (const { mode, Token } of TOKENS) { + describe(`using ${Token._json.contractName}`, function () { + beforeEach(async function () { + this.chainId = await web3.eth.getChainId(); + this.token = await Token.new(tokenName, tokenSymbol, tokenName); + this.mock = await Governor.new( + name, // name + votingDelay, // initialVotingDelay + votingPeriod, // initialVotingPeriod + 0, // initialProposalThreshold + this.token.address, // tokenAddress + 10, // quorumNumeratorValue + ); + this.receiver = await CallReceiver.new(); - this.helper = new GovernorHelper(this.mock); + this.helper = new GovernorHelper(this.mock, mode); - await web3.eth.sendTransaction({ from: owner, to: this.mock.address, value }); + await web3.eth.sendTransaction({ from: owner, to: this.mock.address, value }); - await this.token.$_mint(owner, tokenSupply); - await this.helper.delegate({ token: this.token, to: voter1, value: web3.utils.toWei('10') }, { from: owner }); - await this.helper.delegate({ token: this.token, to: voter2, value: web3.utils.toWei('7') }, { from: owner }); - await this.helper.delegate({ token: this.token, to: voter3, value: web3.utils.toWei('5') }, { from: owner }); - await this.helper.delegate({ token: this.token, to: voter4, value: web3.utils.toWei('2') }, { from: owner }); + await this.token.$_mint(owner, tokenSupply); + await this.helper.delegate({ token: this.token, to: voter1, value: web3.utils.toWei('10') }, { from: owner }); + await this.helper.delegate({ token: this.token, to: voter2, value: web3.utils.toWei('7') }, { from: owner }); + await this.helper.delegate({ token: this.token, to: voter3, value: web3.utils.toWei('5') }, { from: owner }); + await this.helper.delegate({ token: this.token, to: voter4, value: web3.utils.toWei('2') }, { from: owner }); - this.proposal = this.helper.setProposal( - [ - { - target: this.receiver.address, - data: this.receiver.contract.methods.mockFunction().encodeABI(), - value, - }, - ], - '', - ); - }); + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.address, + data: this.receiver.contract.methods.mockFunction().encodeABI(), + value, + }, + ], + '', + ); + }); - shouldSupportInterfaces(['ERC165', 'ERC1155Receiver', 'Governor', 'GovernorWithParams']); + shouldSupportInterfaces(['ERC165', 'ERC1155Receiver', 'Governor', 'GovernorWithParams']); + shouldBehaveLikeEIP6372(mode); - it('deployment check', async function () { - expect(await this.mock.name()).to.be.equal(name); - expect(await this.mock.token()).to.be.equal(this.token.address); - expect(await this.mock.votingDelay()).to.be.bignumber.equal(votingDelay); - expect(await this.mock.votingPeriod()).to.be.bignumber.equal(votingPeriod); - expect(await this.mock.quorum(0)).to.be.bignumber.equal('0'); - expect(await this.mock.COUNTING_MODE()).to.be.equal('support=bravo&quorum=for,abstain'); - }); + it('deployment check', async function () { + expect(await this.mock.name()).to.be.equal(name); + expect(await this.mock.token()).to.be.equal(this.token.address); + expect(await this.mock.votingDelay()).to.be.bignumber.equal(votingDelay); + expect(await this.mock.votingPeriod()).to.be.bignumber.equal(votingPeriod); + expect(await this.mock.quorum(0)).to.be.bignumber.equal('0'); + expect(await this.mock.COUNTING_MODE()).to.be.equal('support=bravo&quorum=for,abstain'); + }); - it('nominal workflow', async function () { - // Before - expect(await this.mock.hasVoted(this.proposal.id, owner)).to.be.equal(false); - expect(await this.mock.hasVoted(this.proposal.id, voter1)).to.be.equal(false); - expect(await this.mock.hasVoted(this.proposal.id, voter2)).to.be.equal(false); - expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(value); - expect(await web3.eth.getBalance(this.receiver.address)).to.be.bignumber.equal('0'); + it('nominal workflow', async function () { + // Before + expect(await this.mock.$_proposalProposer(this.proposal.id)).to.be.equal(constants.ZERO_ADDRESS); + expect(await this.mock.hasVoted(this.proposal.id, owner)).to.be.equal(false); + expect(await this.mock.hasVoted(this.proposal.id, voter1)).to.be.equal(false); + expect(await this.mock.hasVoted(this.proposal.id, voter2)).to.be.equal(false); + expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(value); + expect(await web3.eth.getBalance(this.receiver.address)).to.be.bignumber.equal('0'); - // Run proposal - const txPropose = await this.helper.propose({ from: proposer }); + // Run proposal + const txPropose = await this.helper.propose({ from: proposer }); - expectEvent(txPropose, 'ProposalCreated', { - proposalId: this.proposal.id, - proposer, - targets: this.proposal.targets, - // values: this.proposal.values, - signatures: this.proposal.signatures, - calldatas: this.proposal.data, - startBlock: new BN(txPropose.receipt.blockNumber).add(votingDelay), - endBlock: new BN(txPropose.receipt.blockNumber).add(votingDelay).add(votingPeriod), - description: this.proposal.description, - }); + expectEvent(txPropose, 'ProposalCreated', { + proposalId: this.proposal.id, + proposer, + targets: this.proposal.targets, + // values: this.proposal.values, + signatures: this.proposal.signatures, + calldatas: this.proposal.data, + voteStart: web3.utils.toBN(await clockFromReceipt[mode](txPropose.receipt)).add(votingDelay), + voteEnd: web3.utils + .toBN(await clockFromReceipt[mode](txPropose.receipt)) + .add(votingDelay) + .add(votingPeriod), + description: this.proposal.description, + }); - await this.helper.waitForSnapshot(); + await this.helper.waitForSnapshot(); - expectEvent( - await this.helper.vote({ support: Enums.VoteType.For, reason: 'This is nice' }, { from: voter1 }), - 'VoteCast', - { - voter: voter1, - support: Enums.VoteType.For, - reason: 'This is nice', - weight: web3.utils.toWei('10'), - }, - ); + expectEvent( + await this.helper.vote({ support: Enums.VoteType.For, reason: 'This is nice' }, { from: voter1 }), + 'VoteCast', + { + voter: voter1, + support: Enums.VoteType.For, + reason: 'This is nice', + weight: web3.utils.toWei('10'), + }, + ); - expectEvent(await this.helper.vote({ support: Enums.VoteType.For }, { from: voter2 }), 'VoteCast', { - voter: voter2, - support: Enums.VoteType.For, - weight: web3.utils.toWei('7'), - }); + expectEvent(await this.helper.vote({ support: Enums.VoteType.For }, { from: voter2 }), 'VoteCast', { + voter: voter2, + support: Enums.VoteType.For, + weight: web3.utils.toWei('7'), + }); - expectEvent(await this.helper.vote({ support: Enums.VoteType.Against }, { from: voter3 }), 'VoteCast', { - voter: voter3, - support: Enums.VoteType.Against, - weight: web3.utils.toWei('5'), - }); + expectEvent(await this.helper.vote({ support: Enums.VoteType.Against }, { from: voter3 }), 'VoteCast', { + voter: voter3, + support: Enums.VoteType.Against, + weight: web3.utils.toWei('5'), + }); - expectEvent(await this.helper.vote({ support: Enums.VoteType.Abstain }, { from: voter4 }), 'VoteCast', { - voter: voter4, - support: Enums.VoteType.Abstain, - weight: web3.utils.toWei('2'), - }); + expectEvent(await this.helper.vote({ support: Enums.VoteType.Abstain }, { from: voter4 }), 'VoteCast', { + voter: voter4, + support: Enums.VoteType.Abstain, + weight: web3.utils.toWei('2'), + }); - await this.helper.waitForDeadline(); + await this.helper.waitForDeadline(); - const txExecute = await this.helper.execute(); + const txExecute = await this.helper.execute(); - expectEvent(txExecute, 'ProposalExecuted', { proposalId: this.proposal.id }); + expectEvent(txExecute, 'ProposalExecuted', { proposalId: this.proposal.id }); - await expectEvent.inTransaction(txExecute.tx, this.receiver, 'MockFunctionCalled'); + await expectEvent.inTransaction(txExecute.tx, this.receiver, 'MockFunctionCalled'); - // After - expect(await this.mock.hasVoted(this.proposal.id, owner)).to.be.equal(false); - expect(await this.mock.hasVoted(this.proposal.id, voter1)).to.be.equal(true); - expect(await this.mock.hasVoted(this.proposal.id, voter2)).to.be.equal(true); - expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal('0'); - expect(await web3.eth.getBalance(this.receiver.address)).to.be.bignumber.equal(value); - }); + // After + expect(await this.mock.$_proposalProposer(this.proposal.id)).to.be.equal(proposer); + expect(await this.mock.hasVoted(this.proposal.id, owner)).to.be.equal(false); + expect(await this.mock.hasVoted(this.proposal.id, voter1)).to.be.equal(true); + expect(await this.mock.hasVoted(this.proposal.id, voter2)).to.be.equal(true); + expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal('0'); + expect(await web3.eth.getBalance(this.receiver.address)).to.be.bignumber.equal(value); + }); - it('vote with signature', async function () { - const voterBySig = Wallet.generate(); - const voterBySigAddress = web3.utils.toChecksumAddress(voterBySig.getAddressString()); + it('vote with signature', async function () { + const voterBySig = Wallet.generate(); + const voterBySigAddress = web3.utils.toChecksumAddress(voterBySig.getAddressString()); - const signature = (contract, message) => - getDomain(contract) - .then(domain => ({ - primaryType: 'Ballot', - types: { - EIP712Domain: domainType(domain), - Ballot: [ - { name: 'proposalId', type: 'uint256' }, - { name: 'support', type: 'uint8' }, + const signature = (contract, message) => + getDomain(contract) + .then(domain => ({ + primaryType: 'Ballot', + types: { + EIP712Domain: domainType(domain), + Ballot: [ + { name: 'proposalId', type: 'uint256' }, + { name: 'support', type: 'uint8' }, + ], + }, + domain, + message, + })) + .then(data => ethSigUtil.signTypedMessage(voterBySig.getPrivateKey(), { data })) + .then(fromRpcSig); + + await this.token.delegate(voterBySigAddress, { from: voter1 }); + + // Run proposal + await this.helper.propose(); + await this.helper.waitForSnapshot(); + expectEvent(await this.helper.vote({ support: Enums.VoteType.For, signature }), 'VoteCast', { + voter: voterBySigAddress, + support: Enums.VoteType.For, + }); + await this.helper.waitForDeadline(); + await this.helper.execute(); + + // After + expect(await this.mock.hasVoted(this.proposal.id, owner)).to.be.equal(false); + expect(await this.mock.hasVoted(this.proposal.id, voter1)).to.be.equal(false); + expect(await this.mock.hasVoted(this.proposal.id, voter2)).to.be.equal(false); + expect(await this.mock.hasVoted(this.proposal.id, voterBySigAddress)).to.be.equal(true); + }); + + it('send ethers', async function () { + const empty = web3.utils.toChecksumAddress(web3.utils.randomHex(20)); + + this.proposal = this.helper.setProposal( + [ + { + target: empty, + value, + }, + ], + '', + ); + + // Before + expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(value); + expect(await web3.eth.getBalance(empty)).to.be.bignumber.equal('0'); + + // Run proposal + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await this.helper.execute(); + + // After + expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal('0'); + expect(await web3.eth.getBalance(empty)).to.be.bignumber.equal(value); + }); + + describe('should revert', function () { + describe('on propose', function () { + it('if proposal already exists', async function () { + await this.helper.propose(); + await expectRevert(this.helper.propose(), 'Governor: proposal already exists'); + }); + }); + + describe('on vote', function () { + it('if proposal does not exist', async function () { + await expectRevert( + this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }), + 'Governor: unknown proposal id', + ); + }); + + it('if voting has not started', async function () { + await this.helper.propose(); + await expectRevert( + this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }), + 'Governor: vote not currently active', + ); + }); + + it('if support value is invalid', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await expectRevert( + this.helper.vote({ support: web3.utils.toBN('255') }), + 'GovernorVotingSimple: invalid value for enum VoteType', + ); + }); + + it('if vote was already casted', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await expectRevert( + this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }), + 'GovernorVotingSimple: vote already cast', + ); + }); + + it('if voting is over', async function () { + await this.helper.propose(); + await this.helper.waitForDeadline(); + await expectRevert( + this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }), + 'Governor: vote not currently active', + ); + }); + }); + + describe('on execute', function () { + it('if proposal does not exist', async function () { + await expectRevert(this.helper.execute(), 'Governor: unknown proposal id'); + }); + + it('if quorum is not reached', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter3 }); + await expectRevert(this.helper.execute(), 'Governor: proposal not successful'); + }); + + it('if score not reached', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.Against }, { from: voter1 }); + await expectRevert(this.helper.execute(), 'Governor: proposal not successful'); + }); + + it('if voting is not over', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await expectRevert(this.helper.execute(), 'Governor: proposal not successful'); + }); + + it('if receiver revert without reason', async function () { + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.address, + data: this.receiver.contract.methods.mockFunctionRevertsNoReason().encodeABI(), + }, + ], + '', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await expectRevert(this.helper.execute(), 'Governor: call reverted without message'); + }); + + it('if receiver revert with reason', async function () { + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.address, + data: this.receiver.contract.methods.mockFunctionRevertsReason().encodeABI(), + }, + ], + '', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await expectRevert(this.helper.execute(), 'CallReceiverMock: reverting'); + }); + + it('if proposal was already executed', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await this.helper.execute(); + await expectRevert(this.helper.execute(), 'Governor: proposal not successful'); + }); + }); + }); + + describe('state', function () { + it('Unset', async function () { + await expectRevert(this.mock.state(this.proposal.id), 'Governor: unknown proposal id'); + }); + + it('Pending & Active', async function () { + await this.helper.propose(); + expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Pending); + await this.helper.waitForSnapshot(); + expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Pending); + await this.helper.waitForSnapshot(+1); + expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Active); + }); + + it('Defeated', async function () { + await this.helper.propose(); + await this.helper.waitForDeadline(); + expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Active); + await this.helper.waitForDeadline(+1); + expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Defeated); + }); + + it('Succeeded', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Active); + await this.helper.waitForDeadline(+1); + expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Succeeded); + }); + + it('Executed', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await this.helper.execute(); + expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Executed); + }); + }); + + describe('cancel', function () { + describe('internal', function () { + it('before proposal', async function () { + await expectRevert(this.helper.cancel('internal'), 'Governor: unknown proposal id'); + }); + + it('after proposal', async function () { + await this.helper.propose(); + + await this.helper.cancel('internal'); + expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled); + + await this.helper.waitForSnapshot(); + await expectRevert( + this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }), + 'Governor: vote not currently active', + ); + }); + + it('after vote', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + + await this.helper.cancel('internal'); + expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled); + + await this.helper.waitForDeadline(); + await expectRevert(this.helper.execute(), 'Governor: proposal not successful'); + }); + + it('after deadline', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + + await this.helper.cancel('internal'); + expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled); + + await expectRevert(this.helper.execute(), 'Governor: proposal not successful'); + }); + + it('after execution', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await this.helper.execute(); + + await expectRevert(this.helper.cancel('internal'), 'Governor: proposal not active'); + }); + }); + + describe('public', function () { + it('before proposal', async function () { + await expectRevert(this.helper.cancel('external'), 'Governor: unknown proposal id'); + }); + + it('after proposal', async function () { + await this.helper.propose(); + + await this.helper.cancel('external'); + }); + + it('after proposal - restricted to proposer', async function () { + await this.helper.propose(); + + await expectRevert(this.helper.cancel('external', { from: owner }), 'Governor: only proposer can cancel'); + }); + + it('after vote started', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(1); // snapshot + 1 block + + await expectRevert(this.helper.cancel('external'), 'Governor: too late to cancel'); + }); + + it('after vote', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + + await expectRevert(this.helper.cancel('external'), 'Governor: too late to cancel'); + }); + + it('after deadline', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + + await expectRevert(this.helper.cancel('external'), 'Governor: too late to cancel'); + }); + + it('after execution', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await this.helper.execute(); + + await expectRevert(this.helper.cancel('external'), 'Governor: too late to cancel'); + }); + }); + }); + + describe('proposal length', function () { + it('empty', async function () { + this.helper.setProposal([], ''); + await expectRevert(this.helper.propose(), 'Governor: empty proposal'); + }); + + it('mismatch #1', async function () { + this.helper.setProposal( + { + targets: [], + values: [web3.utils.toWei('0')], + data: [this.receiver.contract.methods.mockFunction().encodeABI()], + }, + '', + ); + await expectRevert(this.helper.propose(), 'Governor: invalid proposal length'); + }); + + it('mismatch #2', async function () { + this.helper.setProposal( + { + targets: [this.receiver.address], + values: [], + data: [this.receiver.contract.methods.mockFunction().encodeABI()], + }, + '', + ); + await expectRevert(this.helper.propose(), 'Governor: invalid proposal length'); + }); + + it('mismatch #3', async function () { + this.helper.setProposal( + { + targets: [this.receiver.address], + values: [web3.utils.toWei('0')], + data: [], + }, + '', + ); + await expectRevert(this.helper.propose(), 'Governor: invalid proposal length'); + }); + }); + + describe('onlyGovernance updates', function () { + it('setVotingDelay is protected', async function () { + await expectRevert(this.mock.setVotingDelay('0'), 'Governor: onlyGovernance'); + }); + + it('setVotingPeriod is protected', async function () { + await expectRevert(this.mock.setVotingPeriod('32'), 'Governor: onlyGovernance'); + }); + + it('setProposalThreshold is protected', async function () { + await expectRevert(this.mock.setProposalThreshold('1000000000000000000'), 'Governor: onlyGovernance'); + }); + + it('can setVotingDelay through governance', async function () { + this.helper.setProposal( + [ + { + target: this.mock.address, + data: this.mock.contract.methods.setVotingDelay('0').encodeABI(), + }, ], - }, - domain, - message, - })) - .then(data => ethSigUtil.signTypedMessage(voterBySig.getPrivateKey(), { data })) - .then(fromRpcSig); + '', + ); - await this.token.delegate(voterBySigAddress, { from: voter1 }); + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); - // Run proposal - await this.helper.propose(); - await this.helper.waitForSnapshot(); - expectEvent(await this.helper.vote({ support: Enums.VoteType.For, signature }), 'VoteCast', { - voter: voterBySigAddress, - support: Enums.VoteType.For, - }); - await this.helper.waitForDeadline(); - await this.helper.execute(); + expectEvent(await this.helper.execute(), 'VotingDelaySet', { oldVotingDelay: '4', newVotingDelay: '0' }); - // After - expect(await this.mock.hasVoted(this.proposal.id, owner)).to.be.equal(false); - expect(await this.mock.hasVoted(this.proposal.id, voter1)).to.be.equal(false); - expect(await this.mock.hasVoted(this.proposal.id, voter2)).to.be.equal(false); - expect(await this.mock.hasVoted(this.proposal.id, voterBySigAddress)).to.be.equal(true); - }); + expect(await this.mock.votingDelay()).to.be.bignumber.equal('0'); + }); - it('send ethers', async function () { - this.proposal = this.helper.setProposal( - [ - { - target: empty, - value, - }, - ], - '', - ); + it('can setVotingPeriod through governance', async function () { + this.helper.setProposal( + [ + { + target: this.mock.address, + data: this.mock.contract.methods.setVotingPeriod('32').encodeABI(), + }, + ], + '', + ); - // Before - expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(value); - expect(await web3.eth.getBalance(empty)).to.be.bignumber.equal('0'); + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); - // Run proposal - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - await this.helper.execute(); + expectEvent(await this.helper.execute(), 'VotingPeriodSet', { oldVotingPeriod: '16', newVotingPeriod: '32' }); - // After - expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal('0'); - expect(await web3.eth.getBalance(empty)).to.be.bignumber.equal(value); - }); + expect(await this.mock.votingPeriod()).to.be.bignumber.equal('32'); + }); - describe('should revert', function () { - describe('on propose', function () { - it('if proposal already exists', async function () { - await this.helper.propose(); - await expectRevert(this.helper.propose(), 'Governor: proposal already exists'); + it('cannot setVotingPeriod to 0 through governance', async function () { + this.helper.setProposal( + [ + { + target: this.mock.address, + data: this.mock.contract.methods.setVotingPeriod('0').encodeABI(), + }, + ], + '', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + + await expectRevert(this.helper.execute(), 'GovernorSettings: voting period too low'); + }); + + it('can setProposalThreshold to 0 through governance', async function () { + this.helper.setProposal( + [ + { + target: this.mock.address, + data: this.mock.contract.methods.setProposalThreshold('1000000000000000000').encodeABI(), + }, + ], + '', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + + expectEvent(await this.helper.execute(), 'ProposalThresholdSet', { + oldProposalThreshold: '0', + newProposalThreshold: '1000000000000000000', + }); + + expect(await this.mock.proposalThreshold()).to.be.bignumber.equal('1000000000000000000'); + }); + }); + + describe('safe receive', function () { + describe('ERC721', function () { + const name = 'Non Fungible Token'; + const symbol = 'NFT'; + const tokenId = web3.utils.toBN(1); + + beforeEach(async function () { + this.token = await ERC721.new(name, symbol); + await this.token.$_mint(owner, tokenId); + }); + + it('can receive an ERC721 safeTransfer', async function () { + await this.token.safeTransferFrom(owner, this.mock.address, tokenId, { from: owner }); + }); + }); + + describe('ERC1155', function () { + const uri = 'https://token-cdn-domain/{id}.json'; + const tokenIds = { + 1: web3.utils.toBN(1000), + 2: web3.utils.toBN(2000), + 3: web3.utils.toBN(3000), + }; + + beforeEach(async function () { + this.token = await ERC1155.new(uri); + await this.token.$_mintBatch(owner, Object.keys(tokenIds), Object.values(tokenIds), '0x'); + }); + + it('can receive ERC1155 safeTransfer', async function () { + await this.token.safeTransferFrom( + owner, + this.mock.address, + ...Object.entries(tokenIds)[0], // id + amount + '0x', + { from: owner }, + ); + }); + + it('can receive ERC1155 safeBatchTransfer', async function () { + await this.token.safeBatchTransferFrom( + owner, + this.mock.address, + Object.keys(tokenIds), + Object.values(tokenIds), + '0x', + { from: owner }, + ); + }); + }); }); }); - - describe('on vote', function () { - it('if proposal does not exist', async function () { - await expectRevert( - this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }), - 'Governor: unknown proposal id', - ); - }); - - it('if voting has not started', async function () { - await this.helper.propose(); - await expectRevert( - this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }), - 'Governor: vote not currently active', - ); - }); - - it('if support value is invalid', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await expectRevert( - this.helper.vote({ support: new BN('255') }), - 'GovernorVotingSimple: invalid value for enum VoteType', - ); - }); - - it('if vote was already casted', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await expectRevert( - this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }), - 'GovernorVotingSimple: vote already cast', - ); - }); - - it('if voting is over', async function () { - await this.helper.propose(); - await this.helper.waitForDeadline(); - await expectRevert( - this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }), - 'Governor: vote not currently active', - ); - }); - }); - - describe('on execute', function () { - it('if proposal does not exist', async function () { - await expectRevert(this.helper.execute(), 'Governor: unknown proposal id'); - }); - - it('if quorum is not reached', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter3 }); - await expectRevert(this.helper.execute(), 'Governor: proposal not successful'); - }); - - it('if score not reached', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.Against }, { from: voter1 }); - await expectRevert(this.helper.execute(), 'Governor: proposal not successful'); - }); - - it('if voting is not over', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await expectRevert(this.helper.execute(), 'Governor: proposal not successful'); - }); - - it('if receiver revert without reason', async function () { - this.proposal = this.helper.setProposal( - [ - { - target: this.receiver.address, - data: this.receiver.contract.methods.mockFunctionRevertsNoReason().encodeABI(), - }, - ], - '', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - await expectRevert(this.helper.execute(), 'Governor: call reverted without message'); - }); - - it('if receiver revert with reason', async function () { - this.proposal = this.helper.setProposal( - [ - { - target: this.receiver.address, - data: this.receiver.contract.methods.mockFunctionRevertsReason().encodeABI(), - }, - ], - '', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - await expectRevert(this.helper.execute(), 'CallReceiverMock: reverting'); - }); - - it('if proposal was already executed', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - await this.helper.execute(); - await expectRevert(this.helper.execute(), 'Governor: proposal not successful'); - }); - }); - }); - - describe('state', function () { - it('Unset', async function () { - await expectRevert(this.mock.state(this.proposal.id), 'Governor: unknown proposal id'); - }); - - it('Pending & Active', async function () { - await this.helper.propose(); - expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Pending); - await this.helper.waitForSnapshot(); - expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Pending); - await this.helper.waitForSnapshot(+1); - expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Active); - }); - - it('Defeated', async function () { - await this.helper.propose(); - await this.helper.waitForDeadline(); - expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Active); - await this.helper.waitForDeadline(+1); - expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Defeated); - }); - - it('Succeeded', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Active); - await this.helper.waitForDeadline(+1); - expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Succeeded); - }); - - it('Executed', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - await this.helper.execute(); - expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Executed); - }); - }); - - describe('cancel', function () { - describe('internal', function () { - it('before proposal', async function () { - await expectRevert(this.helper.cancel('internal'), 'Governor: unknown proposal id'); - }); - - it('after proposal', async function () { - await this.helper.propose(); - - await this.helper.cancel('internal'); - expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled); - - await this.helper.waitForSnapshot(); - await expectRevert( - this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }), - 'Governor: vote not currently active', - ); - }); - - it('after vote', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - - await this.helper.cancel('internal'); - expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled); - - await this.helper.waitForDeadline(); - await expectRevert(this.helper.execute(), 'Governor: proposal not successful'); - }); - - it('after deadline', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - - await this.helper.cancel('internal'); - expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled); - - await expectRevert(this.helper.execute(), 'Governor: proposal not successful'); - }); - - it('after execution', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - await this.helper.execute(); - - await expectRevert(this.helper.cancel('internal'), 'Governor: proposal not active'); - }); - }); - - describe('public', function () { - it('before proposal', async function () { - await expectRevert(this.helper.cancel('external'), 'Governor: unknown proposal id'); - }); - - it('after proposal', async function () { - await this.helper.propose(); - - await this.helper.cancel('external'); - }); - - it('after proposal - restricted to proposer', async function () { - await this.helper.propose(); - - await expectRevert(this.helper.cancel('external', { from: owner }), 'Governor: only proposer can cancel'); - }); - - it('after vote started', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(1); // snapshot + 1 block - - await expectRevert(this.helper.cancel('external'), 'Governor: too late to cancel'); - }); - - it('after vote', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - - await expectRevert(this.helper.cancel('external'), 'Governor: too late to cancel'); - }); - - it('after deadline', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - - await expectRevert(this.helper.cancel('external'), 'Governor: too late to cancel'); - }); - - it('after execution', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - await this.helper.execute(); - - await expectRevert(this.helper.cancel('external'), 'Governor: too late to cancel'); - }); - }); - }); - - describe('proposal length', function () { - it('empty', async function () { - this.helper.setProposal([], ''); - await expectRevert(this.helper.propose(), 'Governor: empty proposal'); - }); - - it('mismatch #1', async function () { - this.helper.setProposal( - { - targets: [], - values: [web3.utils.toWei('0')], - data: [this.receiver.contract.methods.mockFunction().encodeABI()], - }, - '', - ); - await expectRevert(this.helper.propose(), 'Governor: invalid proposal length'); - }); - - it('mismatch #2', async function () { - this.helper.setProposal( - { - targets: [this.receiver.address], - values: [], - data: [this.receiver.contract.methods.mockFunction().encodeABI()], - }, - '', - ); - await expectRevert(this.helper.propose(), 'Governor: invalid proposal length'); - }); - - it('mismatch #3', async function () { - this.helper.setProposal( - { - targets: [this.receiver.address], - values: [web3.utils.toWei('0')], - data: [], - }, - '', - ); - await expectRevert(this.helper.propose(), 'Governor: invalid proposal length'); - }); - }); - - describe('onlyGovernance updates', function () { - it('setVotingDelay is protected', async function () { - await expectRevert(this.mock.setVotingDelay('0'), 'Governor: onlyGovernance'); - }); - - it('setVotingPeriod is protected', async function () { - await expectRevert(this.mock.setVotingPeriod('32'), 'Governor: onlyGovernance'); - }); - - it('setProposalThreshold is protected', async function () { - await expectRevert(this.mock.setProposalThreshold('1000000000000000000'), 'Governor: onlyGovernance'); - }); - - it('can setVotingDelay through governance', async function () { - this.helper.setProposal( - [ - { - target: this.mock.address, - data: this.mock.contract.methods.setVotingDelay('0').encodeABI(), - }, - ], - '', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - - expectEvent(await this.helper.execute(), 'VotingDelaySet', { oldVotingDelay: '4', newVotingDelay: '0' }); - - expect(await this.mock.votingDelay()).to.be.bignumber.equal('0'); - }); - - it('can setVotingPeriod through governance', async function () { - this.helper.setProposal( - [ - { - target: this.mock.address, - data: this.mock.contract.methods.setVotingPeriod('32').encodeABI(), - }, - ], - '', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - - expectEvent(await this.helper.execute(), 'VotingPeriodSet', { oldVotingPeriod: '16', newVotingPeriod: '32' }); - - expect(await this.mock.votingPeriod()).to.be.bignumber.equal('32'); - }); - - it('cannot setVotingPeriod to 0 through governance', async function () { - this.helper.setProposal( - [ - { - target: this.mock.address, - data: this.mock.contract.methods.setVotingPeriod('0').encodeABI(), - }, - ], - '', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - - await expectRevert(this.helper.execute(), 'GovernorSettings: voting period too low'); - }); - - it('can setProposalThreshold to 0 through governance', async function () { - this.helper.setProposal( - [ - { - target: this.mock.address, - data: this.mock.contract.methods.setProposalThreshold('1000000000000000000').encodeABI(), - }, - ], - '', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - - expectEvent(await this.helper.execute(), 'ProposalThresholdSet', { - oldProposalThreshold: '0', - newProposalThreshold: '1000000000000000000', - }); - - expect(await this.mock.proposalThreshold()).to.be.bignumber.equal('1000000000000000000'); - }); - }); - - describe('safe receive', function () { - describe('ERC721', function () { - const name = 'Non Fungible Token'; - const symbol = 'NFT'; - const tokenId = new BN(1); - - beforeEach(async function () { - this.token = await ERC721.new(name, symbol); - await this.token.$_mint(owner, tokenId); - }); - - it('can receive an ERC721 safeTransfer', async function () { - await this.token.safeTransferFrom(owner, this.mock.address, tokenId, { from: owner }); - }); - }); - - describe('ERC1155', function () { - const uri = 'https://token-cdn-domain/{id}.json'; - const tokenIds = { - 1: new BN(1000), - 2: new BN(2000), - 3: new BN(3000), - }; - - beforeEach(async function () { - this.token = await ERC1155.new(uri); - await this.token.$_mintBatch(owner, Object.keys(tokenIds), Object.values(tokenIds), '0x'); - }); - - it('can receive ERC1155 safeTransfer', async function () { - await this.token.safeTransferFrom( - owner, - this.mock.address, - ...Object.entries(tokenIds)[0], // id + amount - '0x', - { from: owner }, - ); - }); - - it('can receive ERC1155 safeBatchTransfer', async function () { - await this.token.safeBatchTransferFrom( - owner, - this.mock.address, - Object.keys(tokenIds), - Object.values(tokenIds), - '0x', - { from: owner }, - ); - }); - }); - }); + } }); diff --git a/test/governance/compatibility/GovernorCompatibilityBravo.test.js b/test/governance/compatibility/GovernorCompatibilityBravo.test.js index 3666c4548..9e551949f 100644 --- a/test/governance/compatibility/GovernorCompatibilityBravo.test.js +++ b/test/governance/compatibility/GovernorCompatibilityBravo.test.js @@ -1,14 +1,16 @@ -const { BN, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); const { expect } = require('chai'); const RLP = require('rlp'); const Enums = require('../../helpers/enums'); const { GovernorHelper } = require('../../helpers/governance'); +const { clockFromReceipt } = require('../../helpers/time'); -const Token = artifacts.require('$ERC20VotesComp'); const Timelock = artifacts.require('CompTimelock'); const Governor = artifacts.require('$GovernorCompatibilityBravoMock'); const CallReceiver = artifacts.require('CallReceiverMock'); +const { shouldBehaveLikeEIP6372 } = require('../utils/EIP6372.behavior'); + function makeContractAddress(creator, nonce) { return web3.utils.toChecksumAddress( web3.utils @@ -18,6 +20,11 @@ function makeContractAddress(creator, nonce) { ); } +const TOKENS = [ + { Token: artifacts.require('$ERC20VotesComp'), mode: 'blocknumber' }, + { Token: artifacts.require('$ERC20VotesCompTimestampMock'), mode: 'timestamp' }, +]; + contract('GovernorCompatibilityBravo', function (accounts) { const [owner, proposer, voter1, voter2, voter3, voter4, other] = accounts; @@ -26,218 +33,236 @@ contract('GovernorCompatibilityBravo', function (accounts) { const tokenName = 'MockToken'; const tokenSymbol = 'MTKN'; const tokenSupply = web3.utils.toWei('100'); - const votingDelay = new BN(4); - const votingPeriod = new BN(16); + const votingDelay = web3.utils.toBN(4); + const votingPeriod = web3.utils.toBN(16); const proposalThreshold = web3.utils.toWei('10'); const value = web3.utils.toWei('1'); - beforeEach(async function () { - const [deployer] = await web3.eth.getAccounts(); + for (const { mode, Token } of TOKENS) { + describe(`using ${Token._json.contractName}`, function () { + beforeEach(async function () { + const [deployer] = await web3.eth.getAccounts(); - this.token = await Token.new(tokenName, tokenSymbol, tokenName); + this.token = await Token.new(tokenName, tokenSymbol, tokenName); - // Need to predict governance address to set it as timelock admin with a delayed transfer - const nonce = await web3.eth.getTransactionCount(deployer); - const predictGovernor = makeContractAddress(deployer, nonce + 1); + // Need to predict governance address to set it as timelock admin with a delayed transfer + const nonce = await web3.eth.getTransactionCount(deployer); + const predictGovernor = makeContractAddress(deployer, nonce + 1); - this.timelock = await Timelock.new(predictGovernor, 2 * 86400); - this.mock = await Governor.new( - name, - votingDelay, - votingPeriod, - proposalThreshold, - this.timelock.address, - this.token.address, - ); - this.receiver = await CallReceiver.new(); + this.timelock = await Timelock.new(predictGovernor, 2 * 86400); + this.mock = await Governor.new( + name, + votingDelay, + votingPeriod, + proposalThreshold, + this.timelock.address, + this.token.address, + ); + this.receiver = await CallReceiver.new(); - this.helper = new GovernorHelper(this.mock); + this.helper = new GovernorHelper(this.mock, mode); - await web3.eth.sendTransaction({ from: owner, to: this.timelock.address, value }); + await web3.eth.sendTransaction({ from: owner, to: this.timelock.address, value }); - await this.token.$_mint(owner, tokenSupply); - await this.helper.delegate({ token: this.token, to: proposer, value: proposalThreshold }, { from: owner }); - await this.helper.delegate({ token: this.token, to: voter1, value: web3.utils.toWei('10') }, { from: owner }); - await this.helper.delegate({ token: this.token, to: voter2, value: web3.utils.toWei('7') }, { from: owner }); - await this.helper.delegate({ token: this.token, to: voter3, value: web3.utils.toWei('5') }, { from: owner }); - await this.helper.delegate({ token: this.token, to: voter4, value: web3.utils.toWei('2') }, { from: owner }); + await this.token.$_mint(owner, tokenSupply); + await this.helper.delegate({ token: this.token, to: proposer, value: proposalThreshold }, { from: owner }); + await this.helper.delegate({ token: this.token, to: voter1, value: web3.utils.toWei('10') }, { from: owner }); + await this.helper.delegate({ token: this.token, to: voter2, value: web3.utils.toWei('7') }, { from: owner }); + await this.helper.delegate({ token: this.token, to: voter3, value: web3.utils.toWei('5') }, { from: owner }); + await this.helper.delegate({ token: this.token, to: voter4, value: web3.utils.toWei('2') }, { from: owner }); - // default proposal - this.proposal = this.helper.setProposal( - [ - { - target: this.receiver.address, - value, - signature: 'mockFunction()', - }, - ], - '', - ); - }); - - it('deployment check', async function () { - expect(await this.mock.name()).to.be.equal(name); - expect(await this.mock.token()).to.be.equal(this.token.address); - expect(await this.mock.votingDelay()).to.be.bignumber.equal(votingDelay); - expect(await this.mock.votingPeriod()).to.be.bignumber.equal(votingPeriod); - expect(await this.mock.quorum(0)).to.be.bignumber.equal('0'); - expect(await this.mock.quorumVotes()).to.be.bignumber.equal('0'); - expect(await this.mock.COUNTING_MODE()).to.be.equal('support=bravo&quorum=bravo'); - }); - - it('nominal workflow', async function () { - // Before - expect(await this.mock.hasVoted(this.proposal.id, owner)).to.be.equal(false); - expect(await this.mock.hasVoted(this.proposal.id, voter1)).to.be.equal(false); - expect(await this.mock.hasVoted(this.proposal.id, voter2)).to.be.equal(false); - expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal('0'); - expect(await web3.eth.getBalance(this.timelock.address)).to.be.bignumber.equal(value); - expect(await web3.eth.getBalance(this.receiver.address)).to.be.bignumber.equal('0'); - - // Run proposal - const txPropose = await this.helper.propose({ from: proposer }); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For, reason: 'This is nice' }, { from: voter1 }); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter2 }); - await this.helper.vote({ support: Enums.VoteType.Against }, { from: voter3 }); - await this.helper.vote({ support: Enums.VoteType.Abstain }, { from: voter4 }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - await this.helper.waitForEta(); - const txExecute = await this.helper.execute(); - - // After - expect(await this.mock.hasVoted(this.proposal.id, owner)).to.be.equal(false); - expect(await this.mock.hasVoted(this.proposal.id, voter1)).to.be.equal(true); - expect(await this.mock.hasVoted(this.proposal.id, voter2)).to.be.equal(true); - expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal('0'); - expect(await web3.eth.getBalance(this.timelock.address)).to.be.bignumber.equal('0'); - expect(await web3.eth.getBalance(this.receiver.address)).to.be.bignumber.equal(value); - - const proposal = await this.mock.proposals(this.proposal.id); - expect(proposal.id).to.be.bignumber.equal(this.proposal.id); - expect(proposal.proposer).to.be.equal(proposer); - expect(proposal.eta).to.be.bignumber.equal(await this.mock.proposalEta(this.proposal.id)); - expect(proposal.startBlock).to.be.bignumber.equal(await this.mock.proposalSnapshot(this.proposal.id)); - expect(proposal.endBlock).to.be.bignumber.equal(await this.mock.proposalDeadline(this.proposal.id)); - expect(proposal.canceled).to.be.equal(false); - expect(proposal.executed).to.be.equal(true); - - const action = await this.mock.getActions(this.proposal.id); - expect(action.targets).to.be.deep.equal(this.proposal.targets); - // expect(action.values).to.be.deep.equal(this.proposal.values); - expect(action.signatures).to.be.deep.equal(this.proposal.signatures); - expect(action.calldatas).to.be.deep.equal(this.proposal.data); - - const voteReceipt1 = await this.mock.getReceipt(this.proposal.id, voter1); - expect(voteReceipt1.hasVoted).to.be.equal(true); - expect(voteReceipt1.support).to.be.bignumber.equal(Enums.VoteType.For); - expect(voteReceipt1.votes).to.be.bignumber.equal(web3.utils.toWei('10')); - - const voteReceipt2 = await this.mock.getReceipt(this.proposal.id, voter2); - expect(voteReceipt2.hasVoted).to.be.equal(true); - expect(voteReceipt2.support).to.be.bignumber.equal(Enums.VoteType.For); - expect(voteReceipt2.votes).to.be.bignumber.equal(web3.utils.toWei('7')); - - const voteReceipt3 = await this.mock.getReceipt(this.proposal.id, voter3); - expect(voteReceipt3.hasVoted).to.be.equal(true); - expect(voteReceipt3.support).to.be.bignumber.equal(Enums.VoteType.Against); - expect(voteReceipt3.votes).to.be.bignumber.equal(web3.utils.toWei('5')); - - const voteReceipt4 = await this.mock.getReceipt(this.proposal.id, voter4); - expect(voteReceipt4.hasVoted).to.be.equal(true); - expect(voteReceipt4.support).to.be.bignumber.equal(Enums.VoteType.Abstain); - expect(voteReceipt4.votes).to.be.bignumber.equal(web3.utils.toWei('2')); - - expectEvent(txPropose, 'ProposalCreated', { - proposalId: this.proposal.id, - proposer, - targets: this.proposal.targets, - // values: this.proposal.values, - signatures: this.proposal.signatures.map(() => ''), // this event doesn't contain the proposal detail - calldatas: this.proposal.fulldata, - startBlock: new BN(txPropose.receipt.blockNumber).add(votingDelay), - endBlock: new BN(txPropose.receipt.blockNumber).add(votingDelay).add(votingPeriod), - description: this.proposal.description, - }); - expectEvent(txExecute, 'ProposalExecuted', { proposalId: this.proposal.id }); - await expectEvent.inTransaction(txExecute.tx, this.receiver, 'MockFunctionCalled'); - }); - - it('double voting is forbidden', async function () { - await this.helper.propose({ from: proposer }); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await expectRevert( - this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }), - 'GovernorCompatibilityBravo: vote already cast', - ); - }); - - it('with function selector and arguments', async function () { - const target = this.receiver.address; - this.helper.setProposal( - [ - { target, data: this.receiver.contract.methods.mockFunction().encodeABI() }, - { target, data: this.receiver.contract.methods.mockFunctionWithArgs(17, 42).encodeABI() }, - { target, signature: 'mockFunctionNonPayable()' }, - { - target, - signature: 'mockFunctionWithArgs(uint256,uint256)', - data: web3.eth.abi.encodeParameters(['uint256', 'uint256'], [18, 43]), - }, - ], - '', - ); - - await this.helper.propose({ from: proposer }); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For, reason: 'This is nice' }, { from: voter1 }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - await this.helper.waitForEta(); - const txExecute = await this.helper.execute(); - - await expectEvent.inTransaction(txExecute.tx, this.receiver, 'MockFunctionCalled'); - await expectEvent.inTransaction(txExecute.tx, this.receiver, 'MockFunctionCalled'); - await expectEvent.inTransaction(txExecute.tx, this.receiver, 'MockFunctionCalledWithArgs', { a: '17', b: '42' }); - await expectEvent.inTransaction(txExecute.tx, this.receiver, 'MockFunctionCalledWithArgs', { a: '18', b: '43' }); - }); - - describe('should revert', function () { - describe('on propose', function () { - it('if proposal does not meet proposalThreshold', async function () { - await expectRevert(this.helper.propose({ from: other }), 'Governor: proposer votes below proposal threshold'); - }); - }); - - describe('on vote', function () { - it('if vote type is invalide', async function () { - await this.helper.propose({ from: proposer }); - await this.helper.waitForSnapshot(); - await expectRevert( - this.helper.vote({ support: 5 }, { from: voter1 }), - 'GovernorCompatibilityBravo: invalid vote type', + // default proposal + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.address, + value, + signature: 'mockFunction()', + }, + ], + '', ); }); - }); - }); - describe('cancel', function () { - it('proposer can cancel', async function () { - await this.helper.propose({ from: proposer }); - await this.helper.cancel('external', { from: proposer }); - }); + shouldBehaveLikeEIP6372(mode); - it('anyone can cancel if proposer drop below threshold', async function () { - await this.helper.propose({ from: proposer }); - await this.token.transfer(voter1, web3.utils.toWei('1'), { from: proposer }); - await this.helper.cancel('external'); - }); + it('deployment check', async function () { + expect(await this.mock.name()).to.be.equal(name); + expect(await this.mock.token()).to.be.equal(this.token.address); + expect(await this.mock.votingDelay()).to.be.bignumber.equal(votingDelay); + expect(await this.mock.votingPeriod()).to.be.bignumber.equal(votingPeriod); + expect(await this.mock.quorum(0)).to.be.bignumber.equal('0'); + expect(await this.mock.quorumVotes()).to.be.bignumber.equal('0'); + expect(await this.mock.COUNTING_MODE()).to.be.equal('support=bravo&quorum=bravo'); + }); - it('cannot cancel is proposer is still above threshold', async function () { - await this.helper.propose({ from: proposer }); - await expectRevert(this.helper.cancel('external'), 'GovernorBravo: proposer above threshold'); + it('nominal workflow', async function () { + // Before + expect(await this.mock.hasVoted(this.proposal.id, owner)).to.be.equal(false); + expect(await this.mock.hasVoted(this.proposal.id, voter1)).to.be.equal(false); + expect(await this.mock.hasVoted(this.proposal.id, voter2)).to.be.equal(false); + expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal('0'); + expect(await web3.eth.getBalance(this.timelock.address)).to.be.bignumber.equal(value); + expect(await web3.eth.getBalance(this.receiver.address)).to.be.bignumber.equal('0'); + + // Run proposal + const txPropose = await this.helper.propose({ from: proposer }); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For, reason: 'This is nice' }, { from: voter1 }); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter2 }); + await this.helper.vote({ support: Enums.VoteType.Against }, { from: voter3 }); + await this.helper.vote({ support: Enums.VoteType.Abstain }, { from: voter4 }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + await this.helper.waitForEta(); + const txExecute = await this.helper.execute(); + + // After + expect(await this.mock.hasVoted(this.proposal.id, owner)).to.be.equal(false); + expect(await this.mock.hasVoted(this.proposal.id, voter1)).to.be.equal(true); + expect(await this.mock.hasVoted(this.proposal.id, voter2)).to.be.equal(true); + expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal('0'); + expect(await web3.eth.getBalance(this.timelock.address)).to.be.bignumber.equal('0'); + expect(await web3.eth.getBalance(this.receiver.address)).to.be.bignumber.equal(value); + + const proposal = await this.mock.proposals(this.proposal.id); + expect(proposal.id).to.be.bignumber.equal(this.proposal.id); + expect(proposal.proposer).to.be.equal(proposer); + expect(proposal.eta).to.be.bignumber.equal(await this.mock.proposalEta(this.proposal.id)); + expect(proposal.startBlock).to.be.bignumber.equal(await this.mock.proposalSnapshot(this.proposal.id)); + expect(proposal.endBlock).to.be.bignumber.equal(await this.mock.proposalDeadline(this.proposal.id)); + expect(proposal.canceled).to.be.equal(false); + expect(proposal.executed).to.be.equal(true); + + const action = await this.mock.getActions(this.proposal.id); + expect(action.targets).to.be.deep.equal(this.proposal.targets); + // expect(action.values).to.be.deep.equal(this.proposal.values); + expect(action.signatures).to.be.deep.equal(this.proposal.signatures); + expect(action.calldatas).to.be.deep.equal(this.proposal.data); + + const voteReceipt1 = await this.mock.getReceipt(this.proposal.id, voter1); + expect(voteReceipt1.hasVoted).to.be.equal(true); + expect(voteReceipt1.support).to.be.bignumber.equal(Enums.VoteType.For); + expect(voteReceipt1.votes).to.be.bignumber.equal(web3.utils.toWei('10')); + + const voteReceipt2 = await this.mock.getReceipt(this.proposal.id, voter2); + expect(voteReceipt2.hasVoted).to.be.equal(true); + expect(voteReceipt2.support).to.be.bignumber.equal(Enums.VoteType.For); + expect(voteReceipt2.votes).to.be.bignumber.equal(web3.utils.toWei('7')); + + const voteReceipt3 = await this.mock.getReceipt(this.proposal.id, voter3); + expect(voteReceipt3.hasVoted).to.be.equal(true); + expect(voteReceipt3.support).to.be.bignumber.equal(Enums.VoteType.Against); + expect(voteReceipt3.votes).to.be.bignumber.equal(web3.utils.toWei('5')); + + const voteReceipt4 = await this.mock.getReceipt(this.proposal.id, voter4); + expect(voteReceipt4.hasVoted).to.be.equal(true); + expect(voteReceipt4.support).to.be.bignumber.equal(Enums.VoteType.Abstain); + expect(voteReceipt4.votes).to.be.bignumber.equal(web3.utils.toWei('2')); + + expectEvent(txPropose, 'ProposalCreated', { + proposalId: this.proposal.id, + proposer, + targets: this.proposal.targets, + // values: this.proposal.values, + signatures: this.proposal.signatures.map(() => ''), // this event doesn't contain the proposal detail + calldatas: this.proposal.fulldata, + voteStart: web3.utils.toBN(await clockFromReceipt[mode](txPropose.receipt)).add(votingDelay), + voteEnd: web3.utils + .toBN(await clockFromReceipt[mode](txPropose.receipt)) + .add(votingDelay) + .add(votingPeriod), + description: this.proposal.description, + }); + expectEvent(txExecute, 'ProposalExecuted', { proposalId: this.proposal.id }); + await expectEvent.inTransaction(txExecute.tx, this.receiver, 'MockFunctionCalled'); + }); + + it('double voting is forbidden', async function () { + await this.helper.propose({ from: proposer }); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await expectRevert( + this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }), + 'GovernorCompatibilityBravo: vote already cast', + ); + }); + + it('with function selector and arguments', async function () { + const target = this.receiver.address; + this.helper.setProposal( + [ + { target, data: this.receiver.contract.methods.mockFunction().encodeABI() }, + { target, data: this.receiver.contract.methods.mockFunctionWithArgs(17, 42).encodeABI() }, + { target, signature: 'mockFunctionNonPayable()' }, + { + target, + signature: 'mockFunctionWithArgs(uint256,uint256)', + data: web3.eth.abi.encodeParameters(['uint256', 'uint256'], [18, 43]), + }, + ], + '', + ); + + await this.helper.propose({ from: proposer }); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For, reason: 'This is nice' }, { from: voter1 }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + await this.helper.waitForEta(); + const txExecute = await this.helper.execute(); + + await expectEvent.inTransaction(txExecute.tx, this.receiver, 'MockFunctionCalled'); + await expectEvent.inTransaction(txExecute.tx, this.receiver, 'MockFunctionCalled'); + await expectEvent.inTransaction(txExecute.tx, this.receiver, 'MockFunctionCalledWithArgs', { + a: '17', + b: '42', + }); + await expectEvent.inTransaction(txExecute.tx, this.receiver, 'MockFunctionCalledWithArgs', { + a: '18', + b: '43', + }); + }); + + describe('should revert', function () { + describe('on propose', function () { + it('if proposal does not meet proposalThreshold', async function () { + await expectRevert( + this.helper.propose({ from: other }), + 'Governor: proposer votes below proposal threshold', + ); + }); + }); + + describe('on vote', function () { + it('if vote type is invalide', async function () { + await this.helper.propose({ from: proposer }); + await this.helper.waitForSnapshot(); + await expectRevert( + this.helper.vote({ support: 5 }, { from: voter1 }), + 'GovernorCompatibilityBravo: invalid vote type', + ); + }); + }); + }); + + describe('cancel', function () { + it('proposer can cancel', async function () { + await this.helper.propose({ from: proposer }); + await this.helper.cancel('external', { from: proposer }); + }); + + it('anyone can cancel if proposer drop below threshold', async function () { + await this.helper.propose({ from: proposer }); + await this.token.transfer(voter1, web3.utils.toWei('1'), { from: proposer }); + await this.helper.cancel('external'); + }); + + it('cannot cancel is proposer is still above threshold', async function () { + await this.helper.propose({ from: proposer }); + await expectRevert(this.helper.cancel('external'), 'GovernorBravo: proposer above threshold'); + }); + }); }); - }); + } }); diff --git a/test/governance/extensions/GovernorComp.test.js b/test/governance/extensions/GovernorComp.test.js index 8d48b4ddc..bfcd0af38 100644 --- a/test/governance/extensions/GovernorComp.test.js +++ b/test/governance/extensions/GovernorComp.test.js @@ -1,12 +1,15 @@ -const { BN } = require('@openzeppelin/test-helpers'); const { expect } = require('chai'); const Enums = require('../../helpers/enums'); const { GovernorHelper } = require('../../helpers/governance'); -const Token = artifacts.require('$ERC20VotesComp'); const Governor = artifacts.require('$GovernorCompMock'); const CallReceiver = artifacts.require('CallReceiverMock'); +const TOKENS = [ + { Token: artifacts.require('$ERC20VotesComp'), mode: 'blocknumber' }, + { Token: artifacts.require('$ERC20VotesCompTimestampMock'), mode: 'timestamp' }, +]; + contract('GovernorComp', function (accounts) { const [owner, voter1, voter2, voter3, voter4] = accounts; @@ -15,67 +18,71 @@ contract('GovernorComp', function (accounts) { const tokenName = 'MockToken'; const tokenSymbol = 'MTKN'; const tokenSupply = web3.utils.toWei('100'); - const votingDelay = new BN(4); - const votingPeriod = new BN(16); + const votingDelay = web3.utils.toBN(4); + const votingPeriod = web3.utils.toBN(16); const value = web3.utils.toWei('1'); - beforeEach(async function () { - this.owner = owner; - this.token = await Token.new(tokenName, tokenSymbol, tokenName); - this.mock = await Governor.new(name, this.token.address); - this.receiver = await CallReceiver.new(); + for (const { mode, Token } of TOKENS) { + describe(`using ${Token._json.contractName}`, function () { + beforeEach(async function () { + this.owner = owner; + this.token = await Token.new(tokenName, tokenSymbol, tokenName); + this.mock = await Governor.new(name, this.token.address); + this.receiver = await CallReceiver.new(); - this.helper = new GovernorHelper(this.mock); + this.helper = new GovernorHelper(this.mock, mode); - await web3.eth.sendTransaction({ from: owner, to: this.mock.address, value }); + await web3.eth.sendTransaction({ from: owner, to: this.mock.address, value }); - await this.token.$_mint(owner, tokenSupply); - await this.helper.delegate({ token: this.token, to: voter1, value: web3.utils.toWei('10') }, { from: owner }); - await this.helper.delegate({ token: this.token, to: voter2, value: web3.utils.toWei('7') }, { from: owner }); - await this.helper.delegate({ token: this.token, to: voter3, value: web3.utils.toWei('5') }, { from: owner }); - await this.helper.delegate({ token: this.token, to: voter4, value: web3.utils.toWei('2') }, { from: owner }); + await this.token.$_mint(owner, tokenSupply); + await this.helper.delegate({ token: this.token, to: voter1, value: web3.utils.toWei('10') }, { from: owner }); + await this.helper.delegate({ token: this.token, to: voter2, value: web3.utils.toWei('7') }, { from: owner }); + await this.helper.delegate({ token: this.token, to: voter3, value: web3.utils.toWei('5') }, { from: owner }); + await this.helper.delegate({ token: this.token, to: voter4, value: web3.utils.toWei('2') }, { from: owner }); - // default proposal - this.proposal = this.helper.setProposal( - [ - { - target: this.receiver.address, - value, - data: this.receiver.contract.methods.mockFunction().encodeABI(), - }, - ], - '', - ); - }); + // default proposal + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.address, + value, + data: this.receiver.contract.methods.mockFunction().encodeABI(), + }, + ], + '', + ); + }); - it('deployment check', async function () { - expect(await this.mock.name()).to.be.equal(name); - expect(await this.mock.token()).to.be.equal(this.token.address); - expect(await this.mock.votingDelay()).to.be.bignumber.equal(votingDelay); - expect(await this.mock.votingPeriod()).to.be.bignumber.equal(votingPeriod); - expect(await this.mock.quorum(0)).to.be.bignumber.equal('0'); - }); + it('deployment check', async function () { + expect(await this.mock.name()).to.be.equal(name); + expect(await this.mock.token()).to.be.equal(this.token.address); + expect(await this.mock.votingDelay()).to.be.bignumber.equal(votingDelay); + expect(await this.mock.votingPeriod()).to.be.bignumber.equal(votingPeriod); + expect(await this.mock.quorum(0)).to.be.bignumber.equal('0'); + }); - it('voting with comp token', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter2 }); - await this.helper.vote({ support: Enums.VoteType.Against }, { from: voter3 }); - await this.helper.vote({ support: Enums.VoteType.Abstain }, { from: voter4 }); - await this.helper.waitForDeadline(); - await this.helper.execute(); + it('voting with comp token', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter2 }); + await this.helper.vote({ support: Enums.VoteType.Against }, { from: voter3 }); + await this.helper.vote({ support: Enums.VoteType.Abstain }, { from: voter4 }); + await this.helper.waitForDeadline(); + await this.helper.execute(); - expect(await this.mock.hasVoted(this.proposal.id, owner)).to.be.equal(false); - expect(await this.mock.hasVoted(this.proposal.id, voter1)).to.be.equal(true); - expect(await this.mock.hasVoted(this.proposal.id, voter2)).to.be.equal(true); - expect(await this.mock.hasVoted(this.proposal.id, voter3)).to.be.equal(true); - expect(await this.mock.hasVoted(this.proposal.id, voter4)).to.be.equal(true); + expect(await this.mock.hasVoted(this.proposal.id, owner)).to.be.equal(false); + expect(await this.mock.hasVoted(this.proposal.id, voter1)).to.be.equal(true); + expect(await this.mock.hasVoted(this.proposal.id, voter2)).to.be.equal(true); + expect(await this.mock.hasVoted(this.proposal.id, voter3)).to.be.equal(true); + expect(await this.mock.hasVoted(this.proposal.id, voter4)).to.be.equal(true); - await this.mock.proposalVotes(this.proposal.id).then(results => { - expect(results.forVotes).to.be.bignumber.equal(web3.utils.toWei('17')); - expect(results.againstVotes).to.be.bignumber.equal(web3.utils.toWei('5')); - expect(results.abstainVotes).to.be.bignumber.equal(web3.utils.toWei('2')); + await this.mock.proposalVotes(this.proposal.id).then(results => { + expect(results.forVotes).to.be.bignumber.equal(web3.utils.toWei('17')); + expect(results.againstVotes).to.be.bignumber.equal(web3.utils.toWei('5')); + expect(results.abstainVotes).to.be.bignumber.equal(web3.utils.toWei('2')); + }); + }); }); - }); + } }); diff --git a/test/governance/extensions/GovernorERC721.test.js b/test/governance/extensions/GovernorERC721.test.js index b0babbd37..c1f424c29 100644 --- a/test/governance/extensions/GovernorERC721.test.js +++ b/test/governance/extensions/GovernorERC721.test.js @@ -1,12 +1,16 @@ -const { BN, expectEvent } = require('@openzeppelin/test-helpers'); +const { expectEvent } = require('@openzeppelin/test-helpers'); const { expect } = require('chai'); const Enums = require('../../helpers/enums'); const { GovernorHelper } = require('../../helpers/governance'); -const Token = artifacts.require('$ERC721Votes'); const Governor = artifacts.require('$GovernorVoteMocks'); const CallReceiver = artifacts.require('CallReceiverMock'); +const TOKENS = [ + { Token: artifacts.require('$ERC721Votes'), mode: 'blocknumber' }, + { Token: artifacts.require('$ERC721VotesTimestampMock'), mode: 'timestamp' }, +]; + contract('GovernorERC721', function (accounts) { const [owner, voter1, voter2, voter3, voter4] = accounts; @@ -14,94 +18,98 @@ contract('GovernorERC721', function (accounts) { // const version = '1'; const tokenName = 'MockNFToken'; const tokenSymbol = 'MTKN'; - const NFT0 = new BN(0); - const NFT1 = new BN(1); - const NFT2 = new BN(2); - const NFT3 = new BN(3); - const NFT4 = new BN(4); - const votingDelay = new BN(4); - const votingPeriod = new BN(16); + const NFT0 = web3.utils.toBN(0); + const NFT1 = web3.utils.toBN(1); + const NFT2 = web3.utils.toBN(2); + const NFT3 = web3.utils.toBN(3); + const NFT4 = web3.utils.toBN(4); + const votingDelay = web3.utils.toBN(4); + const votingPeriod = web3.utils.toBN(16); const value = web3.utils.toWei('1'); - beforeEach(async function () { - this.owner = owner; - this.token = await Token.new(tokenName, tokenSymbol, tokenName, '1'); - this.mock = await Governor.new(name, this.token.address); - this.receiver = await CallReceiver.new(); + for (const { mode, Token } of TOKENS) { + describe(`using ${Token._json.contractName}`, function () { + beforeEach(async function () { + this.owner = owner; + this.token = await Token.new(tokenName, tokenSymbol, tokenName, '1'); + this.mock = await Governor.new(name, this.token.address); + this.receiver = await CallReceiver.new(); - this.helper = new GovernorHelper(this.mock); + this.helper = new GovernorHelper(this.mock, mode); - await web3.eth.sendTransaction({ from: owner, to: this.mock.address, value }); + await web3.eth.sendTransaction({ from: owner, to: this.mock.address, value }); - await Promise.all([NFT0, NFT1, NFT2, NFT3, NFT4].map(tokenId => this.token.$_mint(owner, tokenId))); - await this.helper.delegate({ token: this.token, to: voter1, tokenId: NFT0 }, { from: owner }); - await this.helper.delegate({ token: this.token, to: voter2, tokenId: NFT1 }, { from: owner }); - await this.helper.delegate({ token: this.token, to: voter2, tokenId: NFT2 }, { from: owner }); - await this.helper.delegate({ token: this.token, to: voter3, tokenId: NFT3 }, { from: owner }); - await this.helper.delegate({ token: this.token, to: voter4, tokenId: NFT4 }, { from: owner }); + await Promise.all([NFT0, NFT1, NFT2, NFT3, NFT4].map(tokenId => this.token.$_mint(owner, tokenId))); + await this.helper.delegate({ token: this.token, to: voter1, tokenId: NFT0 }, { from: owner }); + await this.helper.delegate({ token: this.token, to: voter2, tokenId: NFT1 }, { from: owner }); + await this.helper.delegate({ token: this.token, to: voter2, tokenId: NFT2 }, { from: owner }); + await this.helper.delegate({ token: this.token, to: voter3, tokenId: NFT3 }, { from: owner }); + await this.helper.delegate({ token: this.token, to: voter4, tokenId: NFT4 }, { from: owner }); - // default proposal - this.proposal = this.helper.setProposal( - [ - { - target: this.receiver.address, - value, - data: this.receiver.contract.methods.mockFunction().encodeABI(), - }, - ], - '', - ); - }); + // default proposal + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.address, + value, + data: this.receiver.contract.methods.mockFunction().encodeABI(), + }, + ], + '', + ); + }); - it('deployment check', async function () { - expect(await this.mock.name()).to.be.equal(name); - expect(await this.mock.token()).to.be.equal(this.token.address); - expect(await this.mock.votingDelay()).to.be.bignumber.equal(votingDelay); - expect(await this.mock.votingPeriod()).to.be.bignumber.equal(votingPeriod); - expect(await this.mock.quorum(0)).to.be.bignumber.equal('0'); - }); + it('deployment check', async function () { + expect(await this.mock.name()).to.be.equal(name); + expect(await this.mock.token()).to.be.equal(this.token.address); + expect(await this.mock.votingDelay()).to.be.bignumber.equal(votingDelay); + expect(await this.mock.votingPeriod()).to.be.bignumber.equal(votingPeriod); + expect(await this.mock.quorum(0)).to.be.bignumber.equal('0'); + }); - it('voting with ERC721 token', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); + it('voting with ERC721 token', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); - expectEvent(await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }), 'VoteCast', { - voter: voter1, - support: Enums.VoteType.For, - weight: '1', + expectEvent(await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }), 'VoteCast', { + voter: voter1, + support: Enums.VoteType.For, + weight: '1', + }); + + expectEvent(await this.helper.vote({ support: Enums.VoteType.For }, { from: voter2 }), 'VoteCast', { + voter: voter2, + support: Enums.VoteType.For, + weight: '2', + }); + + expectEvent(await this.helper.vote({ support: Enums.VoteType.Against }, { from: voter3 }), 'VoteCast', { + voter: voter3, + support: Enums.VoteType.Against, + weight: '1', + }); + + expectEvent(await this.helper.vote({ support: Enums.VoteType.Abstain }, { from: voter4 }), 'VoteCast', { + voter: voter4, + support: Enums.VoteType.Abstain, + weight: '1', + }); + + await this.helper.waitForDeadline(); + await this.helper.execute(); + + expect(await this.mock.hasVoted(this.proposal.id, owner)).to.be.equal(false); + expect(await this.mock.hasVoted(this.proposal.id, voter1)).to.be.equal(true); + expect(await this.mock.hasVoted(this.proposal.id, voter2)).to.be.equal(true); + expect(await this.mock.hasVoted(this.proposal.id, voter3)).to.be.equal(true); + expect(await this.mock.hasVoted(this.proposal.id, voter4)).to.be.equal(true); + + await this.mock.proposalVotes(this.proposal.id).then(results => { + expect(results.forVotes).to.be.bignumber.equal('3'); + expect(results.againstVotes).to.be.bignumber.equal('1'); + expect(results.abstainVotes).to.be.bignumber.equal('1'); + }); + }); }); - - expectEvent(await this.helper.vote({ support: Enums.VoteType.For }, { from: voter2 }), 'VoteCast', { - voter: voter2, - support: Enums.VoteType.For, - weight: '2', - }); - - expectEvent(await this.helper.vote({ support: Enums.VoteType.Against }, { from: voter3 }), 'VoteCast', { - voter: voter3, - support: Enums.VoteType.Against, - weight: '1', - }); - - expectEvent(await this.helper.vote({ support: Enums.VoteType.Abstain }, { from: voter4 }), 'VoteCast', { - voter: voter4, - support: Enums.VoteType.Abstain, - weight: '1', - }); - - await this.helper.waitForDeadline(); - await this.helper.execute(); - - expect(await this.mock.hasVoted(this.proposal.id, owner)).to.be.equal(false); - expect(await this.mock.hasVoted(this.proposal.id, voter1)).to.be.equal(true); - expect(await this.mock.hasVoted(this.proposal.id, voter2)).to.be.equal(true); - expect(await this.mock.hasVoted(this.proposal.id, voter3)).to.be.equal(true); - expect(await this.mock.hasVoted(this.proposal.id, voter4)).to.be.equal(true); - - await this.mock.proposalVotes(this.proposal.id).then(results => { - expect(results.forVotes).to.be.bignumber.equal('3'); - expect(results.againstVotes).to.be.bignumber.equal('1'); - expect(results.abstainVotes).to.be.bignumber.equal('1'); - }); - }); + } }); diff --git a/test/governance/extensions/GovernorPreventLateQuorum.test.js b/test/governance/extensions/GovernorPreventLateQuorum.test.js index ffec8ace6..f81bd5286 100644 --- a/test/governance/extensions/GovernorPreventLateQuorum.test.js +++ b/test/governance/extensions/GovernorPreventLateQuorum.test.js @@ -1,12 +1,17 @@ -const { BN, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); const { expect } = require('chai'); const Enums = require('../../helpers/enums'); const { GovernorHelper } = require('../../helpers/governance'); +const { clockFromReceipt } = require('../../helpers/time'); -const Token = artifacts.require('$ERC20VotesComp'); const Governor = artifacts.require('$GovernorPreventLateQuorumMock'); const CallReceiver = artifacts.require('CallReceiverMock'); +const TOKENS = [ + { Token: artifacts.require('$ERC20Votes'), mode: 'blocknumber' }, + { Token: artifacts.require('$ERC20VotesTimestampMock'), mode: 'timestamp' }, +]; + contract('GovernorPreventLateQuorum', function (accounts) { const [owner, proposer, voter1, voter2, voter3, voter4] = accounts; @@ -15,158 +20,170 @@ contract('GovernorPreventLateQuorum', function (accounts) { const tokenName = 'MockToken'; const tokenSymbol = 'MTKN'; const tokenSupply = web3.utils.toWei('100'); - const votingDelay = new BN(4); - const votingPeriod = new BN(16); - const lateQuorumVoteExtension = new BN(8); + const votingDelay = web3.utils.toBN(4); + const votingPeriod = web3.utils.toBN(16); + const lateQuorumVoteExtension = web3.utils.toBN(8); const quorum = web3.utils.toWei('1'); const value = web3.utils.toWei('1'); - beforeEach(async function () { - this.owner = owner; - this.token = await Token.new(tokenName, tokenSymbol, tokenName); - this.mock = await Governor.new( - name, - votingDelay, - votingPeriod, - 0, - this.token.address, - lateQuorumVoteExtension, - quorum, - ); - this.receiver = await CallReceiver.new(); + for (const { mode, Token } of TOKENS) { + describe(`using ${Token._json.contractName}`, function () { + beforeEach(async function () { + this.owner = owner; + this.token = await Token.new(tokenName, tokenSymbol, tokenName); + this.mock = await Governor.new( + name, + votingDelay, + votingPeriod, + 0, + this.token.address, + lateQuorumVoteExtension, + quorum, + ); + this.receiver = await CallReceiver.new(); - this.helper = new GovernorHelper(this.mock); + this.helper = new GovernorHelper(this.mock, mode); - await web3.eth.sendTransaction({ from: owner, to: this.mock.address, value }); + await web3.eth.sendTransaction({ from: owner, to: this.mock.address, value }); - await this.token.$_mint(owner, tokenSupply); - await this.helper.delegate({ token: this.token, to: voter1, value: web3.utils.toWei('10') }, { from: owner }); - await this.helper.delegate({ token: this.token, to: voter2, value: web3.utils.toWei('7') }, { from: owner }); - await this.helper.delegate({ token: this.token, to: voter3, value: web3.utils.toWei('5') }, { from: owner }); - await this.helper.delegate({ token: this.token, to: voter4, value: web3.utils.toWei('2') }, { from: owner }); + await this.token.$_mint(owner, tokenSupply); + await this.helper.delegate({ token: this.token, to: voter1, value: web3.utils.toWei('10') }, { from: owner }); + await this.helper.delegate({ token: this.token, to: voter2, value: web3.utils.toWei('7') }, { from: owner }); + await this.helper.delegate({ token: this.token, to: voter3, value: web3.utils.toWei('5') }, { from: owner }); + await this.helper.delegate({ token: this.token, to: voter4, value: web3.utils.toWei('2') }, { from: owner }); - // default proposal - this.proposal = this.helper.setProposal( - [ - { - target: this.receiver.address, - value, - data: this.receiver.contract.methods.mockFunction().encodeABI(), - }, - ], - '', - ); - }); - - it('deployment check', async function () { - expect(await this.mock.name()).to.be.equal(name); - expect(await this.mock.token()).to.be.equal(this.token.address); - expect(await this.mock.votingDelay()).to.be.bignumber.equal(votingDelay); - expect(await this.mock.votingPeriod()).to.be.bignumber.equal(votingPeriod); - expect(await this.mock.quorum(0)).to.be.bignumber.equal(quorum); - expect(await this.mock.lateQuorumVoteExtension()).to.be.bignumber.equal(lateQuorumVoteExtension); - }); - - it('nominal workflow unaffected', async function () { - const txPropose = await this.helper.propose({ from: proposer }); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter2 }); - await this.helper.vote({ support: Enums.VoteType.Against }, { from: voter3 }); - await this.helper.vote({ support: Enums.VoteType.Abstain }, { from: voter4 }); - await this.helper.waitForDeadline(); - await this.helper.execute(); - - expect(await this.mock.hasVoted(this.proposal.id, owner)).to.be.equal(false); - expect(await this.mock.hasVoted(this.proposal.id, voter1)).to.be.equal(true); - expect(await this.mock.hasVoted(this.proposal.id, voter2)).to.be.equal(true); - expect(await this.mock.hasVoted(this.proposal.id, voter3)).to.be.equal(true); - expect(await this.mock.hasVoted(this.proposal.id, voter4)).to.be.equal(true); - - await this.mock.proposalVotes(this.proposal.id).then(results => { - expect(results.forVotes).to.be.bignumber.equal(web3.utils.toWei('17')); - expect(results.againstVotes).to.be.bignumber.equal(web3.utils.toWei('5')); - expect(results.abstainVotes).to.be.bignumber.equal(web3.utils.toWei('2')); - }); - - const startBlock = new BN(txPropose.receipt.blockNumber).add(votingDelay); - const endBlock = new BN(txPropose.receipt.blockNumber).add(votingDelay).add(votingPeriod); - expect(await this.mock.proposalSnapshot(this.proposal.id)).to.be.bignumber.equal(startBlock); - expect(await this.mock.proposalDeadline(this.proposal.id)).to.be.bignumber.equal(endBlock); - - expectEvent(txPropose, 'ProposalCreated', { - proposalId: this.proposal.id, - proposer, - targets: this.proposal.targets, - // values: this.proposal.values.map(value => new BN(value)), - signatures: this.proposal.signatures, - calldatas: this.proposal.data, - startBlock, - endBlock, - description: this.proposal.description, - }); - }); - - it('Delay is extended to prevent last minute take-over', async function () { - const txPropose = await this.helper.propose({ from: proposer }); - - // compute original schedule - const startBlock = new BN(txPropose.receipt.blockNumber).add(votingDelay); - const endBlock = new BN(txPropose.receipt.blockNumber).add(votingDelay).add(votingPeriod); - expect(await this.mock.proposalSnapshot(this.proposal.id)).to.be.bignumber.equal(startBlock); - expect(await this.mock.proposalDeadline(this.proposal.id)).to.be.bignumber.equal(endBlock); - - // wait for the last minute to vote - await this.helper.waitForDeadline(-1); - const txVote = await this.helper.vote({ support: Enums.VoteType.For }, { from: voter2 }); - - // cannot execute yet - expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Active); - - // compute new extended schedule - const extendedDeadline = new BN(txVote.receipt.blockNumber).add(lateQuorumVoteExtension); - expect(await this.mock.proposalSnapshot(this.proposal.id)).to.be.bignumber.equal(startBlock); - expect(await this.mock.proposalDeadline(this.proposal.id)).to.be.bignumber.equal(extendedDeadline); - - // still possible to vote - await this.helper.vote({ support: Enums.VoteType.Against }, { from: voter1 }); - - await this.helper.waitForDeadline(); - expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Active); - await this.helper.waitForDeadline(+1); - expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Defeated); - - // check extension event - expectEvent(txVote, 'ProposalExtended', { proposalId: this.proposal.id, extendedDeadline }); - }); - - describe('onlyGovernance updates', function () { - it('setLateQuorumVoteExtension is protected', async function () { - await expectRevert(this.mock.setLateQuorumVoteExtension(0), 'Governor: onlyGovernance'); - }); - - it('can setLateQuorumVoteExtension through governance', async function () { - this.helper.setProposal( - [ - { - target: this.mock.address, - data: this.mock.contract.methods.setLateQuorumVoteExtension('0').encodeABI(), - }, - ], - '', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - - expectEvent(await this.helper.execute(), 'LateQuorumVoteExtensionSet', { - oldVoteExtension: lateQuorumVoteExtension, - newVoteExtension: '0', + // default proposal + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.address, + value, + data: this.receiver.contract.methods.mockFunction().encodeABI(), + }, + ], + '', + ); }); - expect(await this.mock.lateQuorumVoteExtension()).to.be.bignumber.equal('0'); + it('deployment check', async function () { + expect(await this.mock.name()).to.be.equal(name); + expect(await this.mock.token()).to.be.equal(this.token.address); + expect(await this.mock.votingDelay()).to.be.bignumber.equal(votingDelay); + expect(await this.mock.votingPeriod()).to.be.bignumber.equal(votingPeriod); + expect(await this.mock.quorum(0)).to.be.bignumber.equal(quorum); + expect(await this.mock.lateQuorumVoteExtension()).to.be.bignumber.equal(lateQuorumVoteExtension); + }); + + it('nominal workflow unaffected', async function () { + const txPropose = await this.helper.propose({ from: proposer }); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter2 }); + await this.helper.vote({ support: Enums.VoteType.Against }, { from: voter3 }); + await this.helper.vote({ support: Enums.VoteType.Abstain }, { from: voter4 }); + await this.helper.waitForDeadline(); + await this.helper.execute(); + + expect(await this.mock.hasVoted(this.proposal.id, owner)).to.be.equal(false); + expect(await this.mock.hasVoted(this.proposal.id, voter1)).to.be.equal(true); + expect(await this.mock.hasVoted(this.proposal.id, voter2)).to.be.equal(true); + expect(await this.mock.hasVoted(this.proposal.id, voter3)).to.be.equal(true); + expect(await this.mock.hasVoted(this.proposal.id, voter4)).to.be.equal(true); + + await this.mock.proposalVotes(this.proposal.id).then(results => { + expect(results.forVotes).to.be.bignumber.equal(web3.utils.toWei('17')); + expect(results.againstVotes).to.be.bignumber.equal(web3.utils.toWei('5')); + expect(results.abstainVotes).to.be.bignumber.equal(web3.utils.toWei('2')); + }); + + const voteStart = web3.utils.toBN(await clockFromReceipt[mode](txPropose.receipt)).add(votingDelay); + const voteEnd = web3.utils + .toBN(await clockFromReceipt[mode](txPropose.receipt)) + .add(votingDelay) + .add(votingPeriod); + expect(await this.mock.proposalSnapshot(this.proposal.id)).to.be.bignumber.equal(voteStart); + expect(await this.mock.proposalDeadline(this.proposal.id)).to.be.bignumber.equal(voteEnd); + + expectEvent(txPropose, 'ProposalCreated', { + proposalId: this.proposal.id, + proposer, + targets: this.proposal.targets, + // values: this.proposal.values.map(value => web3.utils.toBN(value)), + signatures: this.proposal.signatures, + calldatas: this.proposal.data, + voteStart, + voteEnd, + description: this.proposal.description, + }); + }); + + it('Delay is extended to prevent last minute take-over', async function () { + const txPropose = await this.helper.propose({ from: proposer }); + + // compute original schedule + const startBlock = web3.utils.toBN(await clockFromReceipt[mode](txPropose.receipt)).add(votingDelay); + const endBlock = web3.utils + .toBN(await clockFromReceipt[mode](txPropose.receipt)) + .add(votingDelay) + .add(votingPeriod); + expect(await this.mock.proposalSnapshot(this.proposal.id)).to.be.bignumber.equal(startBlock); + expect(await this.mock.proposalDeadline(this.proposal.id)).to.be.bignumber.equal(endBlock); + + // wait for the last minute to vote + await this.helper.waitForDeadline(-1); + const txVote = await this.helper.vote({ support: Enums.VoteType.For }, { from: voter2 }); + + // cannot execute yet + expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Active); + + // compute new extended schedule + const extendedDeadline = web3.utils + .toBN(await clockFromReceipt[mode](txVote.receipt)) + .add(lateQuorumVoteExtension); + expect(await this.mock.proposalSnapshot(this.proposal.id)).to.be.bignumber.equal(startBlock); + expect(await this.mock.proposalDeadline(this.proposal.id)).to.be.bignumber.equal(extendedDeadline); + + // still possible to vote + await this.helper.vote({ support: Enums.VoteType.Against }, { from: voter1 }); + + await this.helper.waitForDeadline(); + expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Active); + await this.helper.waitForDeadline(+1); + expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Defeated); + + // check extension event + expectEvent(txVote, 'ProposalExtended', { proposalId: this.proposal.id, extendedDeadline }); + }); + + describe('onlyGovernance updates', function () { + it('setLateQuorumVoteExtension is protected', async function () { + await expectRevert(this.mock.setLateQuorumVoteExtension(0), 'Governor: onlyGovernance'); + }); + + it('can setLateQuorumVoteExtension through governance', async function () { + this.helper.setProposal( + [ + { + target: this.mock.address, + data: this.mock.contract.methods.setLateQuorumVoteExtension('0').encodeABI(), + }, + ], + '', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + + expectEvent(await this.helper.execute(), 'LateQuorumVoteExtensionSet', { + oldVoteExtension: lateQuorumVoteExtension, + newVoteExtension: '0', + }); + + expect(await this.mock.lateQuorumVoteExtension()).to.be.bignumber.equal('0'); + }); + }); }); - }); + } }); diff --git a/test/governance/extensions/GovernorTimelockCompound.test.js b/test/governance/extensions/GovernorTimelockCompound.test.js index 446d74999..23d0adbd8 100644 --- a/test/governance/extensions/GovernorTimelockCompound.test.js +++ b/test/governance/extensions/GovernorTimelockCompound.test.js @@ -1,4 +1,4 @@ -const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); const { expect } = require('chai'); const RLP = require('rlp'); const Enums = require('../../helpers/enums'); @@ -6,7 +6,6 @@ const { GovernorHelper } = require('../../helpers/governance'); const { shouldSupportInterfaces } = require('../../utils/introspection/SupportsInterface.behavior'); -const Token = artifacts.require('$ERC20Votes'); const Timelock = artifacts.require('CompTimelock'); const Governor = artifacts.require('$GovernorTimelockCompoundMock'); const CallReceiver = artifacts.require('CallReceiverMock'); @@ -20,6 +19,11 @@ function makeContractAddress(creator, nonce) { ); } +const TOKENS = [ + { Token: artifacts.require('$ERC20Votes'), mode: 'blocknumber' }, + { Token: artifacts.require('$ERC20VotesTimestampMock'), mode: 'timestamp' }, +]; + contract('GovernorTimelockCompound', function (accounts) { const [owner, voter1, voter2, voter3, voter4, other] = accounts; @@ -28,306 +32,321 @@ contract('GovernorTimelockCompound', function (accounts) { const tokenName = 'MockToken'; const tokenSymbol = 'MTKN'; const tokenSupply = web3.utils.toWei('100'); - const votingDelay = new BN(4); - const votingPeriod = new BN(16); + const votingDelay = web3.utils.toBN(4); + const votingPeriod = web3.utils.toBN(16); const value = web3.utils.toWei('1'); - beforeEach(async function () { - const [deployer] = await web3.eth.getAccounts(); - - this.token = await Token.new(tokenName, tokenSymbol, tokenName); - - // Need to predict governance address to set it as timelock admin with a delayed transfer - const nonce = await web3.eth.getTransactionCount(deployer); - const predictGovernor = makeContractAddress(deployer, nonce + 1); - - this.timelock = await Timelock.new(predictGovernor, 2 * 86400); - this.mock = await Governor.new(name, votingDelay, votingPeriod, 0, this.timelock.address, this.token.address, 0); - this.receiver = await CallReceiver.new(); - - this.helper = new GovernorHelper(this.mock); - - await web3.eth.sendTransaction({ from: owner, to: this.timelock.address, value }); - - await this.token.$_mint(owner, tokenSupply); - await this.helper.delegate({ token: this.token, to: voter1, value: web3.utils.toWei('10') }, { from: owner }); - await this.helper.delegate({ token: this.token, to: voter2, value: web3.utils.toWei('7') }, { from: owner }); - await this.helper.delegate({ token: this.token, to: voter3, value: web3.utils.toWei('5') }, { from: owner }); - await this.helper.delegate({ token: this.token, to: voter4, value: web3.utils.toWei('2') }, { from: owner }); - - // default proposal - this.proposal = this.helper.setProposal( - [ - { - target: this.receiver.address, - value, - data: this.receiver.contract.methods.mockFunction().encodeABI(), - }, - ], - '', - ); - }); - - shouldSupportInterfaces(['ERC165', 'Governor', 'GovernorWithParams', 'GovernorTimelock']); - - it("doesn't accept ether transfers", async function () { - await expectRevert.unspecified(web3.eth.sendTransaction({ from: owner, to: this.mock.address, value: 1 })); - }); - - it('post deployment check', async function () { - expect(await this.mock.name()).to.be.equal(name); - expect(await this.mock.token()).to.be.equal(this.token.address); - expect(await this.mock.votingDelay()).to.be.bignumber.equal(votingDelay); - expect(await this.mock.votingPeriod()).to.be.bignumber.equal(votingPeriod); - expect(await this.mock.quorum(0)).to.be.bignumber.equal('0'); - - expect(await this.mock.timelock()).to.be.equal(this.timelock.address); - expect(await this.timelock.admin()).to.be.equal(this.mock.address); - }); - - it('nominal', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter2 }); - await this.helper.vote({ support: Enums.VoteType.Against }, { from: voter3 }); - await this.helper.vote({ support: Enums.VoteType.Abstain }, { from: voter4 }); - await this.helper.waitForDeadline(); - const txQueue = await this.helper.queue(); - const eta = await this.mock.proposalEta(this.proposal.id); - await this.helper.waitForEta(); - const txExecute = await this.helper.execute(); - - expectEvent(txQueue, 'ProposalQueued', { proposalId: this.proposal.id }); - await expectEvent.inTransaction(txQueue.tx, this.timelock, 'QueueTransaction', { eta }); - - expectEvent(txExecute, 'ProposalExecuted', { proposalId: this.proposal.id }); - await expectEvent.inTransaction(txExecute.tx, this.timelock, 'ExecuteTransaction', { eta }); - await expectEvent.inTransaction(txExecute.tx, this.receiver, 'MockFunctionCalled'); - }); - - describe('should revert', function () { - describe('on queue', function () { - it('if already queued', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - await expectRevert(this.helper.queue(), 'Governor: proposal not successful'); - }); - - it('if proposal contains duplicate calls', async function () { - const action = { - target: this.token.address, - data: this.token.contract.methods.approve(this.receiver.address, constants.MAX_UINT256).encodeABI(), - }; - this.helper.setProposal([action, action], ''); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - await expectRevert(this.helper.queue(), 'GovernorTimelockCompound: identical proposal action already queued'); - await expectRevert(this.helper.execute(), 'GovernorTimelockCompound: proposal not yet queued'); - }); - }); - - describe('on execute', function () { - it('if not queued', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(+1); - - expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Succeeded); - - await expectRevert(this.helper.execute(), 'GovernorTimelockCompound: proposal not yet queued'); - }); - - it('if too early', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - - expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Queued); - - await expectRevert( - this.helper.execute(), - "Timelock::executeTransaction: Transaction hasn't surpassed time lock", - ); - }); - - it('if too late', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - await this.helper.waitForEta(+30 * 86400); - - expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Expired); - - await expectRevert(this.helper.execute(), 'Governor: proposal not successful'); - }); - - it('if already executed', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - await this.helper.waitForEta(); - await this.helper.execute(); - await expectRevert(this.helper.execute(), 'Governor: proposal not successful'); - }); - }); - }); - - describe('cancel', function () { - it('cancel before queue prevents scheduling', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - - expectEvent(await this.helper.cancel('internal'), 'ProposalCanceled', { proposalId: this.proposal.id }); - - expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled); - await expectRevert(this.helper.queue(), 'Governor: proposal not successful'); - }); - - it('cancel after queue prevents executing', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - - expectEvent(await this.helper.cancel('internal'), 'ProposalCanceled', { proposalId: this.proposal.id }); - - expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled); - await expectRevert(this.helper.execute(), 'Governor: proposal not successful'); - }); - }); - - describe('onlyGovernance', function () { - describe('relay', function () { + for (const { mode, Token } of TOKENS) { + describe(`using ${Token._json.contractName}`, function () { beforeEach(async function () { - await this.token.$_mint(this.mock.address, 1); - }); + const [deployer] = await web3.eth.getAccounts(); - it('is protected', async function () { - await expectRevert( - this.mock.relay(this.token.address, 0, this.token.contract.methods.transfer(other, 1).encodeABI()), - 'Governor: onlyGovernance', + this.token = await Token.new(tokenName, tokenSymbol, tokenName); + + // Need to predict governance address to set it as timelock admin with a delayed transfer + const nonce = await web3.eth.getTransactionCount(deployer); + const predictGovernor = makeContractAddress(deployer, nonce + 1); + + this.timelock = await Timelock.new(predictGovernor, 2 * 86400); + this.mock = await Governor.new( + name, + votingDelay, + votingPeriod, + 0, + this.timelock.address, + this.token.address, + 0, ); - }); + this.receiver = await CallReceiver.new(); - it('can be executed through governance', async function () { - this.helper.setProposal( + this.helper = new GovernorHelper(this.mock, mode); + + await web3.eth.sendTransaction({ from: owner, to: this.timelock.address, value }); + + await this.token.$_mint(owner, tokenSupply); + await this.helper.delegate({ token: this.token, to: voter1, value: web3.utils.toWei('10') }, { from: owner }); + await this.helper.delegate({ token: this.token, to: voter2, value: web3.utils.toWei('7') }, { from: owner }); + await this.helper.delegate({ token: this.token, to: voter3, value: web3.utils.toWei('5') }, { from: owner }); + await this.helper.delegate({ token: this.token, to: voter4, value: web3.utils.toWei('2') }, { from: owner }); + + // default proposal + this.proposal = this.helper.setProposal( [ { - target: this.mock.address, - data: this.mock.contract.methods - .relay(this.token.address, 0, this.token.contract.methods.transfer(other, 1).encodeABI()) - .encodeABI(), + target: this.receiver.address, + value, + data: this.receiver.contract.methods.mockFunction().encodeABI(), }, ], '', ); + }); - expect(await this.token.balanceOf(this.mock.address), 1); - expect(await this.token.balanceOf(other), 0); + shouldSupportInterfaces(['ERC165', 'Governor', 'GovernorWithParams', 'GovernorTimelock']); + it("doesn't accept ether transfers", async function () { + await expectRevert.unspecified(web3.eth.sendTransaction({ from: owner, to: this.mock.address, value: 1 })); + }); + + it('post deployment check', async function () { + expect(await this.mock.name()).to.be.equal(name); + expect(await this.mock.token()).to.be.equal(this.token.address); + expect(await this.mock.votingDelay()).to.be.bignumber.equal(votingDelay); + expect(await this.mock.votingPeriod()).to.be.bignumber.equal(votingPeriod); + expect(await this.mock.quorum(0)).to.be.bignumber.equal('0'); + + expect(await this.mock.timelock()).to.be.equal(this.timelock.address); + expect(await this.timelock.admin()).to.be.equal(this.mock.address); + }); + + it('nominal', async function () { await this.helper.propose(); await this.helper.waitForSnapshot(); await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter2 }); + await this.helper.vote({ support: Enums.VoteType.Against }, { from: voter3 }); + await this.helper.vote({ support: Enums.VoteType.Abstain }, { from: voter4 }); await this.helper.waitForDeadline(); - await this.helper.queue(); + const txQueue = await this.helper.queue(); + const eta = await this.mock.proposalEta(this.proposal.id); await this.helper.waitForEta(); const txExecute = await this.helper.execute(); - expect(await this.token.balanceOf(this.mock.address), 0); - expect(await this.token.balanceOf(other), 1); + expectEvent(txQueue, 'ProposalQueued', { proposalId: this.proposal.id }); + await expectEvent.inTransaction(txQueue.tx, this.timelock, 'QueueTransaction', { eta }); - await expectEvent.inTransaction(txExecute.tx, this.token, 'Transfer', { - from: this.mock.address, - to: other, - value: '1', + expectEvent(txExecute, 'ProposalExecuted', { proposalId: this.proposal.id }); + await expectEvent.inTransaction(txExecute.tx, this.timelock, 'ExecuteTransaction', { eta }); + await expectEvent.inTransaction(txExecute.tx, this.receiver, 'MockFunctionCalled'); + }); + + describe('should revert', function () { + describe('on queue', function () { + it('if already queued', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + await expectRevert(this.helper.queue(), 'Governor: proposal not successful'); + }); + + it('if proposal contains duplicate calls', async function () { + const action = { + target: this.token.address, + data: this.token.contract.methods.approve(this.receiver.address, constants.MAX_UINT256).encodeABI(), + }; + this.helper.setProposal([action, action], ''); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await expectRevert( + this.helper.queue(), + 'GovernorTimelockCompound: identical proposal action already queued', + ); + await expectRevert(this.helper.execute(), 'GovernorTimelockCompound: proposal not yet queued'); + }); + }); + + describe('on execute', function () { + it('if not queued', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(+1); + + expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Succeeded); + + await expectRevert(this.helper.execute(), 'GovernorTimelockCompound: proposal not yet queued'); + }); + + it('if too early', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + + expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Queued); + + await expectRevert( + this.helper.execute(), + "Timelock::executeTransaction: Transaction hasn't surpassed time lock", + ); + }); + + it('if too late', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + await this.helper.waitForEta(+30 * 86400); + + expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Expired); + + await expectRevert(this.helper.execute(), 'Governor: proposal not successful'); + }); + + it('if already executed', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + await this.helper.waitForEta(); + await this.helper.execute(); + await expectRevert(this.helper.execute(), 'Governor: proposal not successful'); + }); + }); + }); + + describe('cancel', function () { + it('cancel before queue prevents scheduling', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + + expectEvent(await this.helper.cancel('internal'), 'ProposalCanceled', { proposalId: this.proposal.id }); + + expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled); + await expectRevert(this.helper.queue(), 'Governor: proposal not successful'); + }); + + it('cancel after queue prevents executing', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + + expectEvent(await this.helper.cancel('internal'), 'ProposalCanceled', { proposalId: this.proposal.id }); + + expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled); + await expectRevert(this.helper.execute(), 'Governor: proposal not successful'); + }); + }); + + describe('onlyGovernance', function () { + describe('relay', function () { + beforeEach(async function () { + await this.token.$_mint(this.mock.address, 1); + }); + + it('is protected', async function () { + await expectRevert( + this.mock.relay(this.token.address, 0, this.token.contract.methods.transfer(other, 1).encodeABI()), + 'Governor: onlyGovernance', + ); + }); + + it('can be executed through governance', async function () { + this.helper.setProposal( + [ + { + target: this.mock.address, + data: this.mock.contract.methods + .relay(this.token.address, 0, this.token.contract.methods.transfer(other, 1).encodeABI()) + .encodeABI(), + }, + ], + '', + ); + + expect(await this.token.balanceOf(this.mock.address), 1); + expect(await this.token.balanceOf(other), 0); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + await this.helper.waitForEta(); + const txExecute = await this.helper.execute(); + + expect(await this.token.balanceOf(this.mock.address), 0); + expect(await this.token.balanceOf(other), 1); + + await expectEvent.inTransaction(txExecute.tx, this.token, 'Transfer', { + from: this.mock.address, + to: other, + value: '1', + }); + }); + }); + + describe('updateTimelock', function () { + beforeEach(async function () { + this.newTimelock = await Timelock.new(this.mock.address, 7 * 86400); + }); + + it('is protected', async function () { + await expectRevert(this.mock.updateTimelock(this.newTimelock.address), 'Governor: onlyGovernance'); + }); + + it('can be executed through governance to', async function () { + this.helper.setProposal( + [ + { + target: this.timelock.address, + data: this.timelock.contract.methods.setPendingAdmin(owner).encodeABI(), + }, + { + target: this.mock.address, + data: this.mock.contract.methods.updateTimelock(this.newTimelock.address).encodeABI(), + }, + ], + '', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + await this.helper.waitForEta(); + const txExecute = await this.helper.execute(); + + expectEvent(txExecute, 'TimelockChange', { + oldTimelock: this.timelock.address, + newTimelock: this.newTimelock.address, + }); + + expect(await this.mock.timelock()).to.be.bignumber.equal(this.newTimelock.address); + }); + }); + + it('can transfer timelock to new governor', async function () { + const newGovernor = await Governor.new(name, 8, 32, 0, this.timelock.address, this.token.address, 0); + this.helper.setProposal( + [ + { + target: this.timelock.address, + data: this.timelock.contract.methods.setPendingAdmin(newGovernor.address).encodeABI(), + }, + ], + '', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + await this.helper.waitForEta(); + const txExecute = await this.helper.execute(); + + await expectEvent.inTransaction(txExecute.tx, this.timelock, 'NewPendingAdmin', { + newPendingAdmin: newGovernor.address, + }); + + await newGovernor.__acceptAdmin(); + expect(await this.timelock.admin()).to.be.bignumber.equal(newGovernor.address); }); }); }); - - describe('updateTimelock', function () { - beforeEach(async function () { - this.newTimelock = await Timelock.new(this.mock.address, 7 * 86400); - }); - - it('is protected', async function () { - await expectRevert(this.mock.updateTimelock(this.newTimelock.address), 'Governor: onlyGovernance'); - }); - - it('can be executed through governance to', async function () { - this.helper.setProposal( - [ - { - target: this.timelock.address, - data: this.timelock.contract.methods.setPendingAdmin(owner).encodeABI(), - }, - { - target: this.mock.address, - data: this.mock.contract.methods.updateTimelock(this.newTimelock.address).encodeABI(), - }, - ], - '', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - await this.helper.waitForEta(); - const txExecute = await this.helper.execute(); - - expectEvent(txExecute, 'TimelockChange', { - oldTimelock: this.timelock.address, - newTimelock: this.newTimelock.address, - }); - - expect(await this.mock.timelock()).to.be.bignumber.equal(this.newTimelock.address); - }); - }); - - it('can transfer timelock to new governor', async function () { - const newGovernor = await Governor.new(name, 8, 32, 0, this.timelock.address, this.token.address, 0); - this.helper.setProposal( - [ - { - target: this.timelock.address, - data: this.timelock.contract.methods.setPendingAdmin(newGovernor.address).encodeABI(), - }, - ], - '', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - await this.helper.waitForEta(); - const txExecute = await this.helper.execute(); - - await expectEvent.inTransaction(txExecute.tx, this.timelock, 'NewPendingAdmin', { - newPendingAdmin: newGovernor.address, - }); - - await newGovernor.__acceptAdmin(); - expect(await this.timelock.admin()).to.be.bignumber.equal(newGovernor.address); - }); - }); + } }); diff --git a/test/governance/extensions/GovernorTimelockControl.test.js b/test/governance/extensions/GovernorTimelockControl.test.js index 2a55787cb..ef50dc708 100644 --- a/test/governance/extensions/GovernorTimelockControl.test.js +++ b/test/governance/extensions/GovernorTimelockControl.test.js @@ -1,15 +1,19 @@ -const { BN, constants, expectEvent, expectRevert, time } = require('@openzeppelin/test-helpers'); +const { constants, expectEvent, expectRevert, time } = require('@openzeppelin/test-helpers'); const { expect } = require('chai'); const Enums = require('../../helpers/enums'); const { GovernorHelper } = require('../../helpers/governance'); const { shouldSupportInterfaces } = require('../../utils/introspection/SupportsInterface.behavior'); -const Token = artifacts.require('$ERC20Votes'); const Timelock = artifacts.require('TimelockController'); const Governor = artifacts.require('$GovernorTimelockControlMock'); const CallReceiver = artifacts.require('CallReceiverMock'); +const TOKENS = [ + { Token: artifacts.require('$ERC20Votes'), mode: 'blocknumber' }, + { Token: artifacts.require('$ERC20VotesTimestampMock'), mode: 'timestamp' }, +]; + contract('GovernorTimelockControl', function (accounts) { const [owner, voter1, voter2, voter3, voter4, other] = accounts; @@ -23,372 +27,419 @@ contract('GovernorTimelockControl', function (accounts) { const tokenName = 'MockToken'; const tokenSymbol = 'MTKN'; const tokenSupply = web3.utils.toWei('100'); - const votingDelay = new BN(4); - const votingPeriod = new BN(16); + const votingDelay = web3.utils.toBN(4); + const votingPeriod = web3.utils.toBN(16); const value = web3.utils.toWei('1'); - beforeEach(async function () { - const [deployer] = await web3.eth.getAccounts(); + for (const { mode, Token } of TOKENS) { + describe(`using ${Token._json.contractName}`, function () { + beforeEach(async function () { + const [deployer] = await web3.eth.getAccounts(); - this.token = await Token.new(tokenName, tokenSymbol, tokenName); - this.timelock = await Timelock.new(3600, [], [], deployer); - this.mock = await Governor.new(name, votingDelay, votingPeriod, 0, this.timelock.address, this.token.address, 0); - this.receiver = await CallReceiver.new(); + this.token = await Token.new(tokenName, tokenSymbol, tokenName); + this.timelock = await Timelock.new(3600, [], [], deployer); + this.mock = await Governor.new( + name, + votingDelay, + votingPeriod, + 0, + this.timelock.address, + this.token.address, + 0, + ); + this.receiver = await CallReceiver.new(); - this.helper = new GovernorHelper(this.mock); + this.helper = new GovernorHelper(this.mock, mode); - this.TIMELOCK_ADMIN_ROLE = await this.timelock.TIMELOCK_ADMIN_ROLE(); - this.PROPOSER_ROLE = await this.timelock.PROPOSER_ROLE(); - this.EXECUTOR_ROLE = await this.timelock.EXECUTOR_ROLE(); - this.CANCELLER_ROLE = await this.timelock.CANCELLER_ROLE(); + this.TIMELOCK_ADMIN_ROLE = await this.timelock.TIMELOCK_ADMIN_ROLE(); + this.PROPOSER_ROLE = await this.timelock.PROPOSER_ROLE(); + this.EXECUTOR_ROLE = await this.timelock.EXECUTOR_ROLE(); + this.CANCELLER_ROLE = await this.timelock.CANCELLER_ROLE(); - await web3.eth.sendTransaction({ from: owner, to: this.timelock.address, value }); + await web3.eth.sendTransaction({ from: owner, to: this.timelock.address, value }); - // normal setup: governor is proposer, everyone is executor, timelock is its own admin - await this.timelock.grantRole(PROPOSER_ROLE, this.mock.address); - await this.timelock.grantRole(PROPOSER_ROLE, owner); - await this.timelock.grantRole(CANCELLER_ROLE, this.mock.address); - await this.timelock.grantRole(CANCELLER_ROLE, owner); - await this.timelock.grantRole(EXECUTOR_ROLE, constants.ZERO_ADDRESS); - await this.timelock.revokeRole(TIMELOCK_ADMIN_ROLE, deployer); + // normal setup: governor is proposer, everyone is executor, timelock is its own admin + await this.timelock.grantRole(PROPOSER_ROLE, this.mock.address); + await this.timelock.grantRole(PROPOSER_ROLE, owner); + await this.timelock.grantRole(CANCELLER_ROLE, this.mock.address); + await this.timelock.grantRole(CANCELLER_ROLE, owner); + await this.timelock.grantRole(EXECUTOR_ROLE, constants.ZERO_ADDRESS); + await this.timelock.revokeRole(TIMELOCK_ADMIN_ROLE, deployer); - await this.token.$_mint(owner, tokenSupply); - await this.helper.delegate({ token: this.token, to: voter1, value: web3.utils.toWei('10') }, { from: owner }); - await this.helper.delegate({ token: this.token, to: voter2, value: web3.utils.toWei('7') }, { from: owner }); - await this.helper.delegate({ token: this.token, to: voter3, value: web3.utils.toWei('5') }, { from: owner }); - await this.helper.delegate({ token: this.token, to: voter4, value: web3.utils.toWei('2') }, { from: owner }); + await this.token.$_mint(owner, tokenSupply); + await this.helper.delegate({ token: this.token, to: voter1, value: web3.utils.toWei('10') }, { from: owner }); + await this.helper.delegate({ token: this.token, to: voter2, value: web3.utils.toWei('7') }, { from: owner }); + await this.helper.delegate({ token: this.token, to: voter3, value: web3.utils.toWei('5') }, { from: owner }); + await this.helper.delegate({ token: this.token, to: voter4, value: web3.utils.toWei('2') }, { from: owner }); - // default proposal - this.proposal = this.helper.setProposal( - [ - { - target: this.receiver.address, - value, - data: this.receiver.contract.methods.mockFunction().encodeABI(), - }, - ], - '', - ); - this.proposal.timelockid = await this.timelock.hashOperationBatch( - ...this.proposal.shortProposal.slice(0, 3), - '0x0', - this.proposal.shortProposal[3], - ); - }); - - shouldSupportInterfaces(['ERC165', 'Governor', 'GovernorWithParams', 'GovernorTimelock']); - - it("doesn't accept ether transfers", async function () { - await expectRevert.unspecified(web3.eth.sendTransaction({ from: owner, to: this.mock.address, value: 1 })); - }); - - it('post deployment check', async function () { - expect(await this.mock.name()).to.be.equal(name); - expect(await this.mock.token()).to.be.equal(this.token.address); - expect(await this.mock.votingDelay()).to.be.bignumber.equal(votingDelay); - expect(await this.mock.votingPeriod()).to.be.bignumber.equal(votingPeriod); - expect(await this.mock.quorum(0)).to.be.bignumber.equal('0'); - - expect(await this.mock.timelock()).to.be.equal(this.timelock.address); - }); - - it('nominal', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter2 }); - await this.helper.vote({ support: Enums.VoteType.Against }, { from: voter3 }); - await this.helper.vote({ support: Enums.VoteType.Abstain }, { from: voter4 }); - await this.helper.waitForDeadline(); - const txQueue = await this.helper.queue(); - await this.helper.waitForEta(); - const txExecute = await this.helper.execute(); - - expectEvent(txQueue, 'ProposalQueued', { proposalId: this.proposal.id }); - await expectEvent.inTransaction(txQueue.tx, this.timelock, 'CallScheduled', { id: this.proposal.timelockid }); - await expectEvent.inTransaction(txQueue.tx, this.timelock, 'CallSalt', { - id: this.proposal.timelockid, - }); - - expectEvent(txExecute, 'ProposalExecuted', { proposalId: this.proposal.id }); - await expectEvent.inTransaction(txExecute.tx, this.timelock, 'CallExecuted', { id: this.proposal.timelockid }); - await expectEvent.inTransaction(txExecute.tx, this.receiver, 'MockFunctionCalled'); - }); - - describe('should revert', function () { - describe('on queue', function () { - it('if already queued', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - await expectRevert(this.helper.queue(), 'Governor: proposal not successful'); - }); - }); - - describe('on execute', function () { - it('if not queued', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(+1); - - expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Succeeded); - - await expectRevert(this.helper.execute(), 'TimelockController: operation is not ready'); - }); - - it('if too early', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - - expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Queued); - - await expectRevert(this.helper.execute(), 'TimelockController: operation is not ready'); - }); - - it('if already executed', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - await this.helper.waitForEta(); - await this.helper.execute(); - await expectRevert(this.helper.execute(), 'Governor: proposal not successful'); - }); - - it('if already executed by another proposer', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - await this.helper.waitForEta(); - - await this.timelock.executeBatch( + // default proposal + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.address, + value, + data: this.receiver.contract.methods.mockFunction().encodeABI(), + }, + ], + '', + ); + this.proposal.timelockid = await this.timelock.hashOperationBatch( ...this.proposal.shortProposal.slice(0, 3), '0x0', this.proposal.shortProposal[3], ); - - await expectRevert(this.helper.execute(), 'Governor: proposal not successful'); - }); - }); - }); - - describe('cancel', function () { - it('cancel before queue prevents scheduling', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - - expectEvent(await this.helper.cancel('internal'), 'ProposalCanceled', { proposalId: this.proposal.id }); - - expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled); - await expectRevert(this.helper.queue(), 'Governor: proposal not successful'); - }); - - it('cancel after queue prevents executing', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - - expectEvent(await this.helper.cancel('internal'), 'ProposalCanceled', { proposalId: this.proposal.id }); - - expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled); - await expectRevert(this.helper.execute(), 'Governor: proposal not successful'); - }); - - it('cancel on timelock is reflected on governor', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - - expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Queued); - - expectEvent(await this.timelock.cancel(this.proposal.timelockid, { from: owner }), 'Cancelled', { - id: this.proposal.timelockid, }); - expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled); - }); - }); + shouldSupportInterfaces(['ERC165', 'Governor', 'GovernorWithParams', 'GovernorTimelock']); - describe('onlyGovernance', function () { - describe('relay', function () { - beforeEach(async function () { - await this.token.$_mint(this.mock.address, 1); + it("doesn't accept ether transfers", async function () { + await expectRevert.unspecified(web3.eth.sendTransaction({ from: owner, to: this.mock.address, value: 1 })); }); - it('is protected', async function () { - await expectRevert( - this.mock.relay(this.token.address, 0, this.token.contract.methods.transfer(other, 1).encodeABI()), - 'Governor: onlyGovernance', - ); + it('post deployment check', async function () { + expect(await this.mock.name()).to.be.equal(name); + expect(await this.mock.token()).to.be.equal(this.token.address); + expect(await this.mock.votingDelay()).to.be.bignumber.equal(votingDelay); + expect(await this.mock.votingPeriod()).to.be.bignumber.equal(votingPeriod); + expect(await this.mock.quorum(0)).to.be.bignumber.equal('0'); + + expect(await this.mock.timelock()).to.be.equal(this.timelock.address); }); - it('can be executed through governance', async function () { - this.helper.setProposal( - [ - { - target: this.mock.address, - data: this.mock.contract.methods - .relay(this.token.address, 0, this.token.contract.methods.transfer(other, 1).encodeABI()) - .encodeABI(), - }, - ], - '', - ); - - expect(await this.token.balanceOf(this.mock.address), 1); - expect(await this.token.balanceOf(other), 0); - + it('nominal', async function () { await this.helper.propose(); await this.helper.waitForSnapshot(); await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter2 }); + await this.helper.vote({ support: Enums.VoteType.Against }, { from: voter3 }); + await this.helper.vote({ support: Enums.VoteType.Abstain }, { from: voter4 }); await this.helper.waitForDeadline(); - await this.helper.queue(); + const txQueue = await this.helper.queue(); await this.helper.waitForEta(); const txExecute = await this.helper.execute(); - expect(await this.token.balanceOf(this.mock.address), 0); - expect(await this.token.balanceOf(other), 1); - - await expectEvent.inTransaction(txExecute.tx, this.token, 'Transfer', { - from: this.mock.address, - to: other, - value: '1', - }); - }); - - it('is payable and can transfer eth to EOA', async function () { - const t2g = web3.utils.toBN(128); // timelock to governor - const g2o = web3.utils.toBN(100); // governor to eoa (other) - - this.helper.setProposal( - [ - { - target: this.mock.address, - value: t2g, - data: this.mock.contract.methods.relay(other, g2o, '0x').encodeABI(), - }, - ], - '', - ); - - expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); - const timelockBalance = await web3.eth.getBalance(this.timelock.address).then(web3.utils.toBN); - const otherBalance = await web3.eth.getBalance(other).then(web3.utils.toBN); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - await this.helper.waitForEta(); - await this.helper.execute(); - - expect(await web3.eth.getBalance(this.timelock.address)).to.be.bignumber.equal(timelockBalance.sub(t2g)); - expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(t2g.sub(g2o)); - expect(await web3.eth.getBalance(other)).to.be.bignumber.equal(otherBalance.add(g2o)); - }); - - it('protected against other proposers', async function () { - await this.timelock.schedule( - this.mock.address, - web3.utils.toWei('0'), - this.mock.contract.methods.relay(constants.ZERO_ADDRESS, 0, '0x').encodeABI(), - constants.ZERO_BYTES32, - constants.ZERO_BYTES32, - 3600, - { from: owner }, - ); - - await time.increase(3600); - - await expectRevert( - this.timelock.execute( - this.mock.address, - web3.utils.toWei('0'), - this.mock.contract.methods.relay(constants.ZERO_ADDRESS, 0, '0x').encodeABI(), - constants.ZERO_BYTES32, - constants.ZERO_BYTES32, - { from: owner }, - ), - 'TimelockController: underlying transaction reverted', - ); - }); - }); - - describe('updateTimelock', function () { - beforeEach(async function () { - this.newTimelock = await Timelock.new(3600, [this.mock.address], [this.mock.address], constants.ZERO_ADDRESS); - }); - - it('is protected', async function () { - await expectRevert(this.mock.updateTimelock(this.newTimelock.address), 'Governor: onlyGovernance'); - }); - - it('can be executed through governance to', async function () { - this.helper.setProposal( - [ - { - target: this.mock.address, - data: this.mock.contract.methods.updateTimelock(this.newTimelock.address).encodeABI(), - }, - ], - '', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - await this.helper.waitForEta(); - const txExecute = await this.helper.execute(); - - expectEvent(txExecute, 'TimelockChange', { - oldTimelock: this.timelock.address, - newTimelock: this.newTimelock.address, + expectEvent(txQueue, 'ProposalQueued', { proposalId: this.proposal.id }); + await expectEvent.inTransaction(txQueue.tx, this.timelock, 'CallScheduled', { id: this.proposal.timelockid }); + await expectEvent.inTransaction(txQueue.tx, this.timelock, 'CallSalt', { + id: this.proposal.timelockid, }); - expect(await this.mock.timelock()).to.be.bignumber.equal(this.newTimelock.address); + expectEvent(txExecute, 'ProposalExecuted', { proposalId: this.proposal.id }); + await expectEvent.inTransaction(txExecute.tx, this.timelock, 'CallExecuted', { id: this.proposal.timelockid }); + await expectEvent.inTransaction(txExecute.tx, this.receiver, 'MockFunctionCalled'); + }); + + describe('should revert', function () { + describe('on queue', function () { + it('if already queued', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter2 }); + await this.helper.vote({ support: Enums.VoteType.Against }, { from: voter3 }); + await this.helper.vote({ support: Enums.VoteType.Abstain }, { from: voter4 }); + await this.helper.waitForDeadline(); + const txQueue = await this.helper.queue(); + await this.helper.waitForEta(); + const txExecute = await this.helper.execute(); + + expectEvent(txQueue, 'ProposalQueued', { proposalId: this.proposal.id }); + await expectEvent.inTransaction(txQueue.tx, this.timelock, 'CallScheduled', { + id: this.proposal.timelockid, + }); + + expectEvent(txExecute, 'ProposalExecuted', { proposalId: this.proposal.id }); + await expectEvent.inTransaction(txExecute.tx, this.timelock, 'CallExecuted', { + id: this.proposal.timelockid, + }); + await expectEvent.inTransaction(txExecute.tx, this.receiver, 'MockFunctionCalled'); + }); + + describe('should revert', function () { + describe('on queue', function () { + it('if already queued', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + await expectRevert(this.helper.queue(), 'Governor: proposal not successful'); + }); + }); + + describe('on execute', function () { + it('if not queued', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(+1); + + expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Succeeded); + + await expectRevert(this.helper.execute(), 'TimelockController: operation is not ready'); + }); + + it('if too early', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + + expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Queued); + + await expectRevert(this.helper.execute(), 'TimelockController: operation is not ready'); + }); + + it('if already executed', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + await this.helper.waitForEta(); + await this.helper.execute(); + await expectRevert(this.helper.execute(), 'Governor: proposal not successful'); + }); + + it('if already executed by another proposer', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + await this.helper.waitForEta(); + + await this.timelock.executeBatch( + ...this.proposal.shortProposal.slice(0, 3), + '0x0', + this.proposal.shortProposal[3], + ); + + await expectRevert(this.helper.execute(), 'Governor: proposal not successful'); + }); + }); + }); + + describe('cancel', function () { + it('cancel before queue prevents scheduling', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + + expectEvent(await this.helper.cancel('internal'), 'ProposalCanceled', { proposalId: this.proposal.id }); + + expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled); + await expectRevert(this.helper.queue(), 'Governor: proposal not successful'); + }); + + it('cancel after queue prevents executing', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + + expectEvent(await this.helper.cancel('internal'), 'ProposalCanceled', { proposalId: this.proposal.id }); + + expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled); + await expectRevert(this.helper.execute(), 'Governor: proposal not successful'); + }); + + it('cancel on timelock is reflected on governor', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + + expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Queued); + + expectEvent(await this.timelock.cancel(this.proposal.timelockid, { from: owner }), 'Cancelled', { + id: this.proposal.timelockid, + }); + + expect(await this.mock.state(this.proposal.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled); + }); + }); + + describe('onlyGovernance', function () { + describe('relay', function () { + beforeEach(async function () { + await this.token.$_mint(this.mock.address, 1); + }); + + it('is protected', async function () { + await expectRevert( + this.mock.relay(this.token.address, 0, this.token.contract.methods.transfer(other, 1).encodeABI()), + 'Governor: onlyGovernance', + ); + }); + + it('can be executed through governance', async function () { + this.helper.setProposal( + [ + { + target: this.mock.address, + data: this.mock.contract.methods + .relay(this.token.address, 0, this.token.contract.methods.transfer(other, 1).encodeABI()) + .encodeABI(), + }, + ], + '', + ); + + expect(await this.token.balanceOf(this.mock.address), 1); + expect(await this.token.balanceOf(other), 0); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + await this.helper.waitForEta(); + const txExecute = await this.helper.execute(); + + expect(await this.token.balanceOf(this.mock.address), 0); + expect(await this.token.balanceOf(other), 1); + + await expectEvent.inTransaction(txExecute.tx, this.token, 'Transfer', { + from: this.mock.address, + to: other, + value: '1', + }); + }); + + it('is payable and can transfer eth to EOA', async function () { + const t2g = web3.utils.toBN(128); // timelock to governor + const g2o = web3.utils.toBN(100); // governor to eoa (other) + + this.helper.setProposal( + [ + { + target: this.mock.address, + value: t2g, + data: this.mock.contract.methods.relay(other, g2o, '0x').encodeABI(), + }, + ], + '', + ); + + expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + const timelockBalance = await web3.eth.getBalance(this.timelock.address).then(web3.utils.toBN); + const otherBalance = await web3.eth.getBalance(other).then(web3.utils.toBN); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + await this.helper.waitForEta(); + await this.helper.execute(); + + expect(await web3.eth.getBalance(this.timelock.address)).to.be.bignumber.equal( + timelockBalance.sub(t2g), + ); + expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(t2g.sub(g2o)); + expect(await web3.eth.getBalance(other)).to.be.bignumber.equal(otherBalance.add(g2o)); + }); + + it('protected against other proposers', async function () { + await this.timelock.schedule( + this.mock.address, + web3.utils.toWei('0'), + this.mock.contract.methods.relay(constants.ZERO_ADDRESS, 0, '0x').encodeABI(), + constants.ZERO_BYTES32, + constants.ZERO_BYTES32, + 3600, + { from: owner }, + ); + + await time.increase(3600); + + await expectRevert( + this.timelock.execute( + this.mock.address, + web3.utils.toWei('0'), + this.mock.contract.methods.relay(constants.ZERO_ADDRESS, 0, '0x').encodeABI(), + constants.ZERO_BYTES32, + constants.ZERO_BYTES32, + { from: owner }, + ), + 'TimelockController: underlying transaction reverted', + ); + }); + }); + + describe('updateTimelock', function () { + beforeEach(async function () { + this.newTimelock = await Timelock.new( + 3600, + [this.mock.address], + [this.mock.address], + constants.ZERO_ADDRESS, + ); + }); + + it('is protected', async function () { + await expectRevert(this.mock.updateTimelock(this.newTimelock.address), 'Governor: onlyGovernance'); + }); + + it('can be executed through governance to', async function () { + this.helper.setProposal( + [ + { + target: this.mock.address, + data: this.mock.contract.methods.updateTimelock(this.newTimelock.address).encodeABI(), + }, + ], + '', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + await this.helper.waitForEta(); + const txExecute = await this.helper.execute(); + + expectEvent(txExecute, 'TimelockChange', { + oldTimelock: this.timelock.address, + newTimelock: this.newTimelock.address, + }); + + expect(await this.mock.timelock()).to.be.bignumber.equal(this.newTimelock.address); + }); + }); + }); + + it('clear queue of pending governor calls', async function () { + this.helper.setProposal( + [ + { + target: this.mock.address, + data: this.mock.contract.methods.nonGovernanceFunction().encodeABI(), + }, + ], + '', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + await this.helper.waitForEta(); + await this.helper.execute(); + + // This path clears _governanceCall as part of the afterExecute call, + // but we have not way to check that the cleanup actually happened other + // then coverage reports. + }); + }); }); }); - }); - - it('clear queue of pending governor calls', async function () { - this.helper.setProposal( - [ - { - target: this.mock.address, - data: this.mock.contract.methods.nonGovernanceFunction().encodeABI(), - }, - ], - '', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - await this.helper.queue(); - await this.helper.waitForEta(); - await this.helper.execute(); - - // This path clears _governanceCall as part of the afterExecute call, - // but we have not way to check that the cleanup actually happened other - // then coverage reports. - }); + } }); diff --git a/test/governance/extensions/GovernorVotesQuorumFraction.test.js b/test/governance/extensions/GovernorVotesQuorumFraction.test.js index 84d36f926..ca915806f 100644 --- a/test/governance/extensions/GovernorVotesQuorumFraction.test.js +++ b/test/governance/extensions/GovernorVotesQuorumFraction.test.js @@ -1,12 +1,17 @@ -const { BN, expectEvent, expectRevert, time } = require('@openzeppelin/test-helpers'); +const { expectEvent, expectRevert, time } = require('@openzeppelin/test-helpers'); const { expect } = require('chai'); const Enums = require('../../helpers/enums'); const { GovernorHelper } = require('../../helpers/governance'); +const { clock } = require('../../helpers/time'); -const Token = artifacts.require('$ERC20Votes'); const Governor = artifacts.require('$GovernorMock'); const CallReceiver = artifacts.require('CallReceiverMock'); +const TOKENS = [ + { Token: artifacts.require('$ERC20Votes'), mode: 'blocknumber' }, + { Token: artifacts.require('$ERC20VotesTimestampMock'), mode: 'timestamp' }, +]; + contract('GovernorVotesQuorumFraction', function (accounts) { const [owner, voter1, voter2, voter3, voter4] = accounts; @@ -14,129 +19,136 @@ contract('GovernorVotesQuorumFraction', function (accounts) { // const version = '1'; const tokenName = 'MockToken'; const tokenSymbol = 'MTKN'; - const tokenSupply = new BN(web3.utils.toWei('100')); - const ratio = new BN(8); // percents - const newRatio = new BN(6); // percents - const votingDelay = new BN(4); - const votingPeriod = new BN(16); + const tokenSupply = web3.utils.toBN(web3.utils.toWei('100')); + const ratio = web3.utils.toBN(8); // percents + const newRatio = web3.utils.toBN(6); // percents + const votingDelay = web3.utils.toBN(4); + const votingPeriod = web3.utils.toBN(16); const value = web3.utils.toWei('1'); - beforeEach(async function () { - this.owner = owner; - this.token = await Token.new(tokenName, tokenSymbol, tokenName); - this.mock = await Governor.new(name, votingDelay, votingPeriod, 0, this.token.address, ratio); - this.receiver = await CallReceiver.new(); + for (const { mode, Token } of TOKENS) { + describe(`using ${Token._json.contractName}`, function () { + beforeEach(async function () { + this.owner = owner; + this.token = await Token.new(tokenName, tokenSymbol, tokenName); + this.mock = await Governor.new(name, votingDelay, votingPeriod, 0, this.token.address, ratio); + this.receiver = await CallReceiver.new(); - this.helper = new GovernorHelper(this.mock); + this.helper = new GovernorHelper(this.mock, mode); - await web3.eth.sendTransaction({ from: owner, to: this.mock.address, value }); + await web3.eth.sendTransaction({ from: owner, to: this.mock.address, value }); - await this.token.$_mint(owner, tokenSupply); - await this.helper.delegate({ token: this.token, to: voter1, value: web3.utils.toWei('10') }, { from: owner }); - await this.helper.delegate({ token: this.token, to: voter2, value: web3.utils.toWei('7') }, { from: owner }); - await this.helper.delegate({ token: this.token, to: voter3, value: web3.utils.toWei('5') }, { from: owner }); - await this.helper.delegate({ token: this.token, to: voter4, value: web3.utils.toWei('2') }, { from: owner }); + await this.token.$_mint(owner, tokenSupply); + await this.helper.delegate({ token: this.token, to: voter1, value: web3.utils.toWei('10') }, { from: owner }); + await this.helper.delegate({ token: this.token, to: voter2, value: web3.utils.toWei('7') }, { from: owner }); + await this.helper.delegate({ token: this.token, to: voter3, value: web3.utils.toWei('5') }, { from: owner }); + await this.helper.delegate({ token: this.token, to: voter4, value: web3.utils.toWei('2') }, { from: owner }); - // default proposal - this.proposal = this.helper.setProposal( - [ - { - target: this.receiver.address, - value, - data: this.receiver.contract.methods.mockFunction().encodeABI(), - }, - ], - '', - ); - }); - - it('deployment check', async function () { - expect(await this.mock.name()).to.be.equal(name); - expect(await this.mock.token()).to.be.equal(this.token.address); - expect(await this.mock.votingDelay()).to.be.bignumber.equal(votingDelay); - expect(await this.mock.votingPeriod()).to.be.bignumber.equal(votingPeriod); - expect(await this.mock.quorum(0)).to.be.bignumber.equal('0'); - expect(await this.mock.quorumNumerator()).to.be.bignumber.equal(ratio); - expect(await this.mock.quorumDenominator()).to.be.bignumber.equal('100'); - expect(await time.latestBlock().then(blockNumber => this.mock.quorum(blockNumber.subn(1)))).to.be.bignumber.equal( - tokenSupply.mul(ratio).divn(100), - ); - }); - - it('quroum reached', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - await this.helper.execute(); - }); - - it('quroum not reached', async function () { - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter2 }); - await this.helper.waitForDeadline(); - await expectRevert(this.helper.execute(), 'Governor: proposal not successful'); - }); - - describe('onlyGovernance updates', function () { - it('updateQuorumNumerator is protected', async function () { - await expectRevert(this.mock.updateQuorumNumerator(newRatio), 'Governor: onlyGovernance'); - }); - - it('can updateQuorumNumerator through governance', async function () { - this.helper.setProposal( - [ - { - target: this.mock.address, - data: this.mock.contract.methods.updateQuorumNumerator(newRatio).encodeABI(), - }, - ], - '', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - - expectEvent(await this.helper.execute(), 'QuorumNumeratorUpdated', { - oldQuorumNumerator: ratio, - newQuorumNumerator: newRatio, + // default proposal + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.address, + value, + data: this.receiver.contract.methods.mockFunction().encodeABI(), + }, + ], + '', + ); }); - expect(await this.mock.quorumNumerator()).to.be.bignumber.equal(newRatio); - expect(await this.mock.quorumDenominator()).to.be.bignumber.equal('100'); + it('deployment check', async function () { + expect(await this.mock.name()).to.be.equal(name); + expect(await this.mock.token()).to.be.equal(this.token.address); + expect(await this.mock.votingDelay()).to.be.bignumber.equal(votingDelay); + expect(await this.mock.votingPeriod()).to.be.bignumber.equal(votingPeriod); + expect(await this.mock.quorum(0)).to.be.bignumber.equal('0'); + expect(await this.mock.quorumNumerator()).to.be.bignumber.equal(ratio); + expect(await this.mock.quorumDenominator()).to.be.bignumber.equal('100'); + expect(await clock[mode]().then(timepoint => this.mock.quorum(timepoint - 1))).to.be.bignumber.equal( + tokenSupply.mul(ratio).divn(100), + ); + }); - // it takes one block for the new quorum to take effect - expect(await time.latestBlock().then(blockNumber => this.mock.quorum(blockNumber.subn(1)))).to.be.bignumber.equal( - tokenSupply.mul(ratio).divn(100), - ); + it('quroum reached', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await this.helper.execute(); + }); - await time.advanceBlock(); + it('quroum not reached', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter2 }); + await this.helper.waitForDeadline(); + await expectRevert(this.helper.execute(), 'Governor: proposal not successful'); + }); - expect(await time.latestBlock().then(blockNumber => this.mock.quorum(blockNumber.subn(1)))).to.be.bignumber.equal( - tokenSupply.mul(newRatio).divn(100), - ); + describe('onlyGovernance updates', function () { + it('updateQuorumNumerator is protected', async function () { + await expectRevert(this.mock.updateQuorumNumerator(newRatio), 'Governor: onlyGovernance'); + }); + + it('can updateQuorumNumerator through governance', async function () { + this.helper.setProposal( + [ + { + target: this.mock.address, + data: this.mock.contract.methods.updateQuorumNumerator(newRatio).encodeABI(), + }, + ], + '', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + + expectEvent(await this.helper.execute(), 'QuorumNumeratorUpdated', { + oldQuorumNumerator: ratio, + newQuorumNumerator: newRatio, + }); + + expect(await this.mock.quorumNumerator()).to.be.bignumber.equal(newRatio); + expect(await this.mock.quorumDenominator()).to.be.bignumber.equal('100'); + + // it takes one block for the new quorum to take effect + expect(await clock[mode]().then(blockNumber => this.mock.quorum(blockNumber - 1))).to.be.bignumber.equal( + tokenSupply.mul(ratio).divn(100), + ); + + await time.advanceBlock(); + + expect(await clock[mode]().then(blockNumber => this.mock.quorum(blockNumber - 1))).to.be.bignumber.equal( + tokenSupply.mul(newRatio).divn(100), + ); + }); + + it('cannot updateQuorumNumerator over the maximum', async function () { + this.helper.setProposal( + [ + { + target: this.mock.address, + data: this.mock.contract.methods.updateQuorumNumerator('101').encodeABI(), + }, + ], + '', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + + await expectRevert( + this.helper.execute(), + 'GovernorVotesQuorumFraction: quorumNumerator over quorumDenominator', + ); + }); + }); }); - - it('cannot updateQuorumNumerator over the maximum', async function () { - this.helper.setProposal( - [ - { - target: this.mock.address, - data: this.mock.contract.methods.updateQuorumNumerator('101').encodeABI(), - }, - ], - '', - ); - - await this.helper.propose(); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); - await this.helper.waitForDeadline(); - - await expectRevert(this.helper.execute(), 'GovernorVotesQuorumFraction: quorumNumerator over quorumDenominator'); - }); - }); + } }); diff --git a/test/governance/extensions/GovernorWithParams.test.js b/test/governance/extensions/GovernorWithParams.test.js index 86ebacc08..4e146947c 100644 --- a/test/governance/extensions/GovernorWithParams.test.js +++ b/test/governance/extensions/GovernorWithParams.test.js @@ -1,4 +1,4 @@ -const { BN, expectEvent } = require('@openzeppelin/test-helpers'); +const { expectEvent } = require('@openzeppelin/test-helpers'); const { expect } = require('chai'); const ethSigUtil = require('eth-sig-util'); const Wallet = require('ethereumjs-wallet').default; @@ -7,17 +7,21 @@ const Enums = require('../../helpers/enums'); const { getDomain, domainType } = require('../../helpers/eip712'); const { GovernorHelper } = require('../../helpers/governance'); -const Token = artifacts.require('$ERC20VotesComp'); const Governor = artifacts.require('$GovernorWithParamsMock'); const CallReceiver = artifacts.require('CallReceiverMock'); const rawParams = { - uintParam: new BN('42'), + uintParam: web3.utils.toBN('42'), strParam: 'These are my params', }; const encodedParams = web3.eth.abi.encodeParameters(['uint256', 'string'], Object.values(rawParams)); +const TOKENS = [ + { Token: artifacts.require('$ERC20Votes'), mode: 'blocknumber' }, + { Token: artifacts.require('$ERC20VotesTimestampMock'), mode: 'timestamp' }, +]; + contract('GovernorWithParams', function (accounts) { const [owner, proposer, voter1, voter2, voter3, voter4] = accounts; @@ -25,141 +29,145 @@ contract('GovernorWithParams', function (accounts) { const tokenName = 'MockToken'; const tokenSymbol = 'MTKN'; const tokenSupply = web3.utils.toWei('100'); - const votingDelay = new BN(4); - const votingPeriod = new BN(16); + const votingDelay = web3.utils.toBN(4); + const votingPeriod = web3.utils.toBN(16); const value = web3.utils.toWei('1'); - beforeEach(async function () { - this.chainId = await web3.eth.getChainId(); - this.token = await Token.new(tokenName, tokenSymbol, tokenName); - this.mock = await Governor.new(name, this.token.address); - this.receiver = await CallReceiver.new(); + for (const { mode, Token } of TOKENS) { + describe(`using ${Token._json.contractName}`, function () { + beforeEach(async function () { + this.chainId = await web3.eth.getChainId(); + this.token = await Token.new(tokenName, tokenSymbol, tokenName); + this.mock = await Governor.new(name, this.token.address); + this.receiver = await CallReceiver.new(); - this.helper = new GovernorHelper(this.mock); + this.helper = new GovernorHelper(this.mock, mode); - await web3.eth.sendTransaction({ from: owner, to: this.mock.address, value }); + await web3.eth.sendTransaction({ from: owner, to: this.mock.address, value }); - await this.token.$_mint(owner, tokenSupply); - await this.helper.delegate({ token: this.token, to: voter1, value: web3.utils.toWei('10') }, { from: owner }); - await this.helper.delegate({ token: this.token, to: voter2, value: web3.utils.toWei('7') }, { from: owner }); - await this.helper.delegate({ token: this.token, to: voter3, value: web3.utils.toWei('5') }, { from: owner }); - await this.helper.delegate({ token: this.token, to: voter4, value: web3.utils.toWei('2') }, { from: owner }); + await this.token.$_mint(owner, tokenSupply); + await this.helper.delegate({ token: this.token, to: voter1, value: web3.utils.toWei('10') }, { from: owner }); + await this.helper.delegate({ token: this.token, to: voter2, value: web3.utils.toWei('7') }, { from: owner }); + await this.helper.delegate({ token: this.token, to: voter3, value: web3.utils.toWei('5') }, { from: owner }); + await this.helper.delegate({ token: this.token, to: voter4, value: web3.utils.toWei('2') }, { from: owner }); - // default proposal - this.proposal = this.helper.setProposal( - [ - { - target: this.receiver.address, - value, - data: this.receiver.contract.methods.mockFunction().encodeABI(), - }, - ], - '', - ); - }); + // default proposal + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.address, + value, + data: this.receiver.contract.methods.mockFunction().encodeABI(), + }, + ], + '', + ); + }); - it('deployment check', async function () { - expect(await this.mock.name()).to.be.equal(name); - expect(await this.mock.token()).to.be.equal(this.token.address); - expect(await this.mock.votingDelay()).to.be.bignumber.equal(votingDelay); - expect(await this.mock.votingPeriod()).to.be.bignumber.equal(votingPeriod); - }); + it('deployment check', async function () { + expect(await this.mock.name()).to.be.equal(name); + expect(await this.mock.token()).to.be.equal(this.token.address); + expect(await this.mock.votingDelay()).to.be.bignumber.equal(votingDelay); + expect(await this.mock.votingPeriod()).to.be.bignumber.equal(votingPeriod); + }); - it('nominal is unaffected', async function () { - await this.helper.propose({ from: proposer }); - await this.helper.waitForSnapshot(); - await this.helper.vote({ support: Enums.VoteType.For, reason: 'This is nice' }, { from: voter1 }); - await this.helper.vote({ support: Enums.VoteType.For }, { from: voter2 }); - await this.helper.vote({ support: Enums.VoteType.Against }, { from: voter3 }); - await this.helper.vote({ support: Enums.VoteType.Abstain }, { from: voter4 }); - await this.helper.waitForDeadline(); - await this.helper.execute(); + it('nominal is unaffected', async function () { + await this.helper.propose({ from: proposer }); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For, reason: 'This is nice' }, { from: voter1 }); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter2 }); + await this.helper.vote({ support: Enums.VoteType.Against }, { from: voter3 }); + await this.helper.vote({ support: Enums.VoteType.Abstain }, { from: voter4 }); + await this.helper.waitForDeadline(); + await this.helper.execute(); - expect(await this.mock.hasVoted(this.proposal.id, owner)).to.be.equal(false); - expect(await this.mock.hasVoted(this.proposal.id, voter1)).to.be.equal(true); - expect(await this.mock.hasVoted(this.proposal.id, voter2)).to.be.equal(true); - expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal('0'); - expect(await web3.eth.getBalance(this.receiver.address)).to.be.bignumber.equal(value); - }); + expect(await this.mock.hasVoted(this.proposal.id, owner)).to.be.equal(false); + expect(await this.mock.hasVoted(this.proposal.id, voter1)).to.be.equal(true); + expect(await this.mock.hasVoted(this.proposal.id, voter2)).to.be.equal(true); + expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal('0'); + expect(await web3.eth.getBalance(this.receiver.address)).to.be.bignumber.equal(value); + }); - it('Voting with params is properly supported', async function () { - await this.helper.propose({ from: proposer }); - await this.helper.waitForSnapshot(); + it('Voting with params is properly supported', async function () { + await this.helper.propose({ from: proposer }); + await this.helper.waitForSnapshot(); - const weight = new BN(web3.utils.toWei('7')).sub(rawParams.uintParam); + const weight = web3.utils.toBN(web3.utils.toWei('7')).sub(rawParams.uintParam); - const tx = await this.helper.vote( - { - support: Enums.VoteType.For, - reason: 'no particular reason', - params: encodedParams, - }, - { from: voter2 }, - ); - - expectEvent(tx, 'CountParams', { ...rawParams }); - expectEvent(tx, 'VoteCastWithParams', { - voter: voter2, - proposalId: this.proposal.id, - support: Enums.VoteType.For, - weight, - reason: 'no particular reason', - params: encodedParams, - }); - - const votes = await this.mock.proposalVotes(this.proposal.id); - expect(votes.forVotes).to.be.bignumber.equal(weight); - }); - - it('Voting with params by signature is properly supported', async function () { - const voterBySig = Wallet.generate(); - const voterBySigAddress = web3.utils.toChecksumAddress(voterBySig.getAddressString()); - - const signature = (contract, message) => - getDomain(contract) - .then(domain => ({ - primaryType: 'ExtendedBallot', - types: { - EIP712Domain: domainType(domain), - ExtendedBallot: [ - { name: 'proposalId', type: 'uint256' }, - { name: 'support', type: 'uint8' }, - { name: 'reason', type: 'string' }, - { name: 'params', type: 'bytes' }, - ], + const tx = await this.helper.vote( + { + support: Enums.VoteType.For, + reason: 'no particular reason', + params: encodedParams, }, - domain, - message, - })) - .then(data => ethSigUtil.signTypedMessage(voterBySig.getPrivateKey(), { data })) - .then(fromRpcSig); + { from: voter2 }, + ); - await this.token.delegate(voterBySigAddress, { from: voter2 }); + expectEvent(tx, 'CountParams', { ...rawParams }); + expectEvent(tx, 'VoteCastWithParams', { + voter: voter2, + proposalId: this.proposal.id, + support: Enums.VoteType.For, + weight, + reason: 'no particular reason', + params: encodedParams, + }); - // Run proposal - await this.helper.propose(); - await this.helper.waitForSnapshot(); + const votes = await this.mock.proposalVotes(this.proposal.id); + expect(votes.forVotes).to.be.bignumber.equal(weight); + }); - const weight = new BN(web3.utils.toWei('7')).sub(rawParams.uintParam); + it('Voting with params by signature is properly supported', async function () { + const voterBySig = Wallet.generate(); + const voterBySigAddress = web3.utils.toChecksumAddress(voterBySig.getAddressString()); - const tx = await this.helper.vote({ - support: Enums.VoteType.For, - reason: 'no particular reason', - params: encodedParams, - signature, + const signature = (contract, message) => + getDomain(contract) + .then(domain => ({ + primaryType: 'ExtendedBallot', + types: { + EIP712Domain: domainType(domain), + ExtendedBallot: [ + { name: 'proposalId', type: 'uint256' }, + { name: 'support', type: 'uint8' }, + { name: 'reason', type: 'string' }, + { name: 'params', type: 'bytes' }, + ], + }, + domain, + message, + })) + .then(data => ethSigUtil.signTypedMessage(voterBySig.getPrivateKey(), { data })) + .then(fromRpcSig); + + await this.token.delegate(voterBySigAddress, { from: voter2 }); + + // Run proposal + await this.helper.propose(); + await this.helper.waitForSnapshot(); + + const weight = web3.utils.toBN(web3.utils.toWei('7')).sub(rawParams.uintParam); + + const tx = await this.helper.vote({ + support: Enums.VoteType.For, + reason: 'no particular reason', + params: encodedParams, + signature, + }); + + expectEvent(tx, 'CountParams', { ...rawParams }); + expectEvent(tx, 'VoteCastWithParams', { + voter: voterBySigAddress, + proposalId: this.proposal.id, + support: Enums.VoteType.For, + weight, + reason: 'no particular reason', + params: encodedParams, + }); + + const votes = await this.mock.proposalVotes(this.proposal.id); + expect(votes.forVotes).to.be.bignumber.equal(weight); + }); }); - - expectEvent(tx, 'CountParams', { ...rawParams }); - expectEvent(tx, 'VoteCastWithParams', { - voter: voterBySigAddress, - proposalId: this.proposal.id, - support: Enums.VoteType.For, - weight, - reason: 'no particular reason', - params: encodedParams, - }); - - const votes = await this.mock.proposalVotes(this.proposal.id); - expect(votes.forVotes).to.be.bignumber.equal(weight); - }); + } }); diff --git a/test/governance/utils/EIP6372.behavior.js b/test/governance/utils/EIP6372.behavior.js new file mode 100644 index 000000000..022ec3568 --- /dev/null +++ b/test/governance/utils/EIP6372.behavior.js @@ -0,0 +1,23 @@ +const { clock } = require('../../helpers/time'); + +function shouldBehaveLikeEIP6372(mode = 'blocknumber') { + describe('should implement EIP6372', function () { + beforeEach(async function () { + this.mock = this.mock ?? this.token ?? this.votes; + }); + + it('clock is correct', async function () { + expect(await this.mock.clock()).to.be.bignumber.equal(await clock[mode]().then(web3.utils.toBN)); + }); + + it('CLOCK_MODE is correct', async function () { + const params = new URLSearchParams(await this.mock.CLOCK_MODE()); + expect(params.get('mode')).to.be.equal(mode); + expect(params.get('from')).to.be.equal(mode == 'blocknumber' ? 'default' : null); + }); + }); +} + +module.exports = { + shouldBehaveLikeEIP6372, +}; diff --git a/test/governance/utils/Votes.behavior.js b/test/governance/utils/Votes.behavior.js index 8fe34dc47..864a2f976 100644 --- a/test/governance/utils/Votes.behavior.js +++ b/test/governance/utils/Votes.behavior.js @@ -6,7 +6,10 @@ const { fromRpcSig } = require('ethereumjs-util'); const ethSigUtil = require('eth-sig-util'); const Wallet = require('ethereumjs-wallet').default; +const { shouldBehaveLikeEIP6372 } = require('./EIP6372.behavior'); + const { getDomain, domainType, domainSeparator } = require('../../helpers/eip712'); +const { clockFromReceipt } = require('../../helpers/time'); const Delegation = [ { name: 'delegatee', type: 'address' }, @@ -14,7 +17,9 @@ const Delegation = [ { name: 'expiry', type: 'uint256' }, ]; -function shouldBehaveLikeVotes() { +function shouldBehaveLikeVotes(mode = 'blocknumber') { + shouldBehaveLikeEIP6372(mode); + describe('run votes workflow', function () { it('initial nonce is 0', async function () { expect(await this.votes.nonces(this.account1)).to.be.bignumber.equal('0'); @@ -57,6 +62,8 @@ function shouldBehaveLikeVotes() { expect(await this.votes.delegates(delegatorAddress)).to.be.equal(ZERO_ADDRESS); const { receipt } = await this.votes.delegateBySig(delegatorAddress, nonce, MAX_UINT256, v, r, s); + const timepoint = await clockFromReceipt[mode](receipt); + expectEvent(receipt, 'DelegateChanged', { delegator: delegatorAddress, fromDelegate: ZERO_ADDRESS, @@ -71,9 +78,9 @@ function shouldBehaveLikeVotes() { expect(await this.votes.delegates(delegatorAddress)).to.be.equal(delegatorAddress); expect(await this.votes.getVotes(delegatorAddress)).to.be.bignumber.equal('1'); - expect(await this.votes.getPastVotes(delegatorAddress, receipt.blockNumber - 1)).to.be.bignumber.equal('0'); + expect(await this.votes.getPastVotes(delegatorAddress, timepoint - 1)).to.be.bignumber.equal('0'); await time.advanceBlock(); - expect(await this.votes.getPastVotes(delegatorAddress, receipt.blockNumber)).to.be.bignumber.equal('1'); + expect(await this.votes.getPastVotes(delegatorAddress, timepoint)).to.be.bignumber.equal('1'); }); it('rejects reused signature', async function () { @@ -157,6 +164,8 @@ function shouldBehaveLikeVotes() { expect(await this.votes.delegates(this.account1)).to.be.equal(ZERO_ADDRESS); const { receipt } = await this.votes.delegate(this.account1, { from: this.account1 }); + const timepoint = await clockFromReceipt[mode](receipt); + expectEvent(receipt, 'DelegateChanged', { delegator: this.account1, fromDelegate: ZERO_ADDRESS, @@ -171,9 +180,9 @@ function shouldBehaveLikeVotes() { expect(await this.votes.delegates(this.account1)).to.be.equal(this.account1); expect(await this.votes.getVotes(this.account1)).to.be.bignumber.equal('1'); - expect(await this.votes.getPastVotes(this.account1, receipt.blockNumber - 1)).to.be.bignumber.equal('0'); + expect(await this.votes.getPastVotes(this.account1, timepoint - 1)).to.be.bignumber.equal('0'); await time.advanceBlock(); - expect(await this.votes.getPastVotes(this.account1, receipt.blockNumber)).to.be.bignumber.equal('1'); + expect(await this.votes.getPastVotes(this.account1, timepoint)).to.be.bignumber.equal('1'); }); it('delegation without tokens', async function () { @@ -202,6 +211,8 @@ function shouldBehaveLikeVotes() { expect(await this.votes.delegates(this.account1)).to.be.equal(this.account1); const { receipt } = await this.votes.delegate(this.account1Delegatee, { from: this.account1 }); + const timepoint = await clockFromReceipt[mode](receipt); + expectEvent(receipt, 'DelegateChanged', { delegator: this.account1, fromDelegate: this.account1, @@ -217,16 +228,16 @@ function shouldBehaveLikeVotes() { previousBalance: '0', newBalance: '1', }); - const prevBlock = receipt.blockNumber - 1; + expect(await this.votes.delegates(this.account1)).to.be.equal(this.account1Delegatee); expect(await this.votes.getVotes(this.account1)).to.be.bignumber.equal('0'); expect(await this.votes.getVotes(this.account1Delegatee)).to.be.bignumber.equal('1'); - expect(await this.votes.getPastVotes(this.account1, receipt.blockNumber - 1)).to.be.bignumber.equal('1'); - expect(await this.votes.getPastVotes(this.account1Delegatee, prevBlock)).to.be.bignumber.equal('0'); + expect(await this.votes.getPastVotes(this.account1, timepoint - 1)).to.be.bignumber.equal('1'); + expect(await this.votes.getPastVotes(this.account1Delegatee, timepoint - 1)).to.be.bignumber.equal('0'); await time.advanceBlock(); - expect(await this.votes.getPastVotes(this.account1, receipt.blockNumber)).to.be.bignumber.equal('0'); - expect(await this.votes.getPastVotes(this.account1Delegatee, receipt.blockNumber)).to.be.bignumber.equal('1'); + expect(await this.votes.getPastVotes(this.account1, timepoint)).to.be.bignumber.equal('0'); + expect(await this.votes.getPastVotes(this.account1Delegatee, timepoint)).to.be.bignumber.equal('1'); }); }); @@ -236,7 +247,7 @@ function shouldBehaveLikeVotes() { }); it('reverts if block number >= current block', async function () { - await expectRevert(this.votes.getPastTotalSupply(5e10), 'block not yet mined'); + await expectRevert(this.votes.getPastTotalSupply(5e10), 'future lookup'); }); it('returns 0 if there are no checkpoints', async function () { @@ -244,22 +255,24 @@ function shouldBehaveLikeVotes() { }); it('returns the latest block if >= last checkpoint block', async function () { - const t1 = await this.votes.$_mint(this.account1, this.NFT0); + const { receipt } = await this.votes.$_mint(this.account1, this.NFT0); + const timepoint = await clockFromReceipt[mode](receipt); await time.advanceBlock(); await time.advanceBlock(); - expect(await this.votes.getPastTotalSupply(t1.receipt.blockNumber - 1)).to.be.bignumber.equal('0'); - expect(await this.votes.getPastTotalSupply(t1.receipt.blockNumber + 1)).to.be.bignumber.equal('1'); + expect(await this.votes.getPastTotalSupply(timepoint - 1)).to.be.bignumber.equal('0'); + expect(await this.votes.getPastTotalSupply(timepoint + 1)).to.be.bignumber.equal('1'); }); it('returns zero if < first checkpoint block', async function () { await time.advanceBlock(); - const t2 = await this.votes.$_mint(this.account1, this.NFT1); + const { receipt } = await this.votes.$_mint(this.account1, this.NFT1); + const timepoint = await clockFromReceipt[mode](receipt); await time.advanceBlock(); await time.advanceBlock(); - expect(await this.votes.getPastTotalSupply(t2.receipt.blockNumber - 1)).to.be.bignumber.equal('0'); - expect(await this.votes.getPastTotalSupply(t2.receipt.blockNumber + 1)).to.be.bignumber.equal('1'); + expect(await this.votes.getPastTotalSupply(timepoint - 1)).to.be.bignumber.equal('0'); + expect(await this.votes.getPastTotalSupply(timepoint + 1)).to.be.bignumber.equal('1'); }); it('generally returns the voting balance at the appropriate checkpoint', async function () { @@ -279,17 +292,23 @@ function shouldBehaveLikeVotes() { await time.advanceBlock(); await time.advanceBlock(); - expect(await this.votes.getPastTotalSupply(t1.receipt.blockNumber - 1)).to.be.bignumber.equal('0'); - expect(await this.votes.getPastTotalSupply(t1.receipt.blockNumber)).to.be.bignumber.equal('1'); - expect(await this.votes.getPastTotalSupply(t1.receipt.blockNumber + 1)).to.be.bignumber.equal('1'); - expect(await this.votes.getPastTotalSupply(t2.receipt.blockNumber)).to.be.bignumber.equal('0'); - expect(await this.votes.getPastTotalSupply(t2.receipt.blockNumber + 1)).to.be.bignumber.equal('0'); - expect(await this.votes.getPastTotalSupply(t3.receipt.blockNumber)).to.be.bignumber.equal('1'); - expect(await this.votes.getPastTotalSupply(t3.receipt.blockNumber + 1)).to.be.bignumber.equal('1'); - expect(await this.votes.getPastTotalSupply(t4.receipt.blockNumber)).to.be.bignumber.equal('0'); - expect(await this.votes.getPastTotalSupply(t4.receipt.blockNumber + 1)).to.be.bignumber.equal('0'); - expect(await this.votes.getPastTotalSupply(t5.receipt.blockNumber)).to.be.bignumber.equal('1'); - expect(await this.votes.getPastTotalSupply(t5.receipt.blockNumber + 1)).to.be.bignumber.equal('1'); + t1.timepoint = await clockFromReceipt[mode](t1.receipt); + t2.timepoint = await clockFromReceipt[mode](t2.receipt); + t3.timepoint = await clockFromReceipt[mode](t3.receipt); + t4.timepoint = await clockFromReceipt[mode](t4.receipt); + t5.timepoint = await clockFromReceipt[mode](t5.receipt); + + expect(await this.votes.getPastTotalSupply(t1.timepoint - 1)).to.be.bignumber.equal('0'); + expect(await this.votes.getPastTotalSupply(t1.timepoint)).to.be.bignumber.equal('1'); + expect(await this.votes.getPastTotalSupply(t1.timepoint + 1)).to.be.bignumber.equal('1'); + expect(await this.votes.getPastTotalSupply(t2.timepoint)).to.be.bignumber.equal('0'); + expect(await this.votes.getPastTotalSupply(t2.timepoint + 1)).to.be.bignumber.equal('0'); + expect(await this.votes.getPastTotalSupply(t3.timepoint)).to.be.bignumber.equal('1'); + expect(await this.votes.getPastTotalSupply(t3.timepoint + 1)).to.be.bignumber.equal('1'); + expect(await this.votes.getPastTotalSupply(t4.timepoint)).to.be.bignumber.equal('0'); + expect(await this.votes.getPastTotalSupply(t4.timepoint + 1)).to.be.bignumber.equal('0'); + expect(await this.votes.getPastTotalSupply(t5.timepoint)).to.be.bignumber.equal('1'); + expect(await this.votes.getPastTotalSupply(t5.timepoint + 1)).to.be.bignumber.equal('1'); }); }); @@ -305,7 +324,7 @@ function shouldBehaveLikeVotes() { describe('getPastVotes', function () { it('reverts if block number >= current block', async function () { - await expectRevert(this.votes.getPastVotes(this.account2, 5e10), 'block not yet mined'); + await expectRevert(this.votes.getPastVotes(this.account2, 5e10), 'future lookup'); }); it('returns 0 if there are no checkpoints', async function () { @@ -313,22 +332,24 @@ function shouldBehaveLikeVotes() { }); it('returns the latest block if >= last checkpoint block', async function () { - const t1 = await this.votes.delegate(this.account2, { from: this.account1 }); + const { receipt } = await this.votes.delegate(this.account2, { from: this.account1 }); + const timepoint = await clockFromReceipt[mode](receipt); await time.advanceBlock(); await time.advanceBlock(); + const latest = await this.votes.getVotes(this.account2); - const nextBlock = t1.receipt.blockNumber + 1; - expect(await this.votes.getPastVotes(this.account2, t1.receipt.blockNumber)).to.be.bignumber.equal(latest); - expect(await this.votes.getPastVotes(this.account2, nextBlock)).to.be.bignumber.equal(latest); + expect(await this.votes.getPastVotes(this.account2, timepoint)).to.be.bignumber.equal(latest); + expect(await this.votes.getPastVotes(this.account2, timepoint + 1)).to.be.bignumber.equal(latest); }); it('returns zero if < first checkpoint block', async function () { await time.advanceBlock(); - const t1 = await this.votes.delegate(this.account2, { from: this.account1 }); + const { receipt } = await this.votes.delegate(this.account2, { from: this.account1 }); + const timepoint = await clockFromReceipt[mode](receipt); await time.advanceBlock(); await time.advanceBlock(); - expect(await this.votes.getPastVotes(this.account2, t1.receipt.blockNumber - 1)).to.be.bignumber.equal('0'); + expect(await this.votes.getPastVotes(this.account2, timepoint - 1)).to.be.bignumber.equal('0'); }); }); }); diff --git a/test/governance/utils/Votes.test.js b/test/governance/utils/Votes.test.js index 7cf998b2d..62b1ab2cd 100644 --- a/test/governance/utils/Votes.test.js +++ b/test/governance/utils/Votes.test.js @@ -3,56 +3,69 @@ const { expectRevert, BN } = require('@openzeppelin/test-helpers'); const { expect } = require('chai'); const { getChainId } = require('../../helpers/chainid'); +const { clockFromReceipt } = require('../../helpers/time'); const { shouldBehaveLikeVotes } = require('./Votes.behavior'); -const Votes = artifacts.require('$VotesMock'); +const MODES = { + blocknumber: artifacts.require('$VotesMock'), + timestamp: artifacts.require('$VotesTimestampMock'), +}; contract('Votes', function (accounts) { const [account1, account2, account3] = accounts; - beforeEach(async function () { - this.name = 'My Vote'; - this.votes = await Votes.new(this.name, '1'); - }); - it('starts with zero votes', async function () { - expect(await this.votes.getTotalSupply()).to.be.bignumber.equal('0'); - }); + for (const [mode, artifact] of Object.entries(MODES)) { + describe(`vote with ${mode}`, function () { + beforeEach(async function () { + this.name = 'My Vote'; + this.votes = await artifact.new(this.name, '1'); + }); - describe('performs voting operations', function () { - beforeEach(async function () { - this.tx1 = await this.votes.$_mint(account1, 1); - this.tx2 = await this.votes.$_mint(account2, 1); - this.tx3 = await this.votes.$_mint(account3, 1); + it('starts with zero votes', async function () { + expect(await this.votes.getTotalSupply()).to.be.bignumber.equal('0'); + }); + + describe('performs voting operations', function () { + beforeEach(async function () { + this.tx1 = await this.votes.$_mint(account1, 1); + this.tx2 = await this.votes.$_mint(account2, 1); + this.tx3 = await this.votes.$_mint(account3, 1); + this.tx1.timepoint = await clockFromReceipt[mode](this.tx1.receipt); + this.tx2.timepoint = await clockFromReceipt[mode](this.tx2.receipt); + this.tx3.timepoint = await clockFromReceipt[mode](this.tx3.receipt); + }); + + it('reverts if block number >= current block', async function () { + await expectRevert(this.votes.getPastTotalSupply(this.tx3.timepoint + 1), 'Votes: future lookup'); + }); + + it('delegates', async function () { + await this.votes.delegate(account3, account2); + + expect(await this.votes.delegates(account3)).to.be.equal(account2); + }); + + it('returns total amount of votes', async function () { + expect(await this.votes.getTotalSupply()).to.be.bignumber.equal('3'); + }); + }); + + describe('performs voting workflow', function () { + beforeEach(async function () { + this.chainId = await getChainId(); + this.account1 = account1; + this.account2 = account2; + this.account1Delegatee = account2; + this.NFT0 = new BN('10000000000000000000000000'); + this.NFT1 = new BN('10'); + this.NFT2 = new BN('20'); + this.NFT3 = new BN('30'); + }); + + // includes EIP6372 behavior check + shouldBehaveLikeVotes(mode); + }); }); - - it('reverts if block number >= current block', async function () { - await expectRevert(this.votes.getPastTotalSupply(this.tx3.receipt.blockNumber + 1), 'Votes: block not yet mined'); - }); - - it('delegates', async function () { - await this.votes.delegate(account3, account2); - - expect(await this.votes.delegates(account3)).to.be.equal(account2); - }); - - it('returns total amount of votes', async function () { - expect(await this.votes.getTotalSupply()).to.be.bignumber.equal('3'); - }); - }); - - describe('performs voting workflow', function () { - beforeEach(async function () { - this.chainId = await getChainId(); - this.account1 = account1; - this.account2 = account2; - this.account1Delegatee = account2; - this.NFT0 = new BN('10000000000000000000000000'); - this.NFT1 = new BN('10'); - this.NFT2 = new BN('20'); - this.NFT3 = new BN('30'); - }); - - shouldBehaveLikeVotes(); - }); + } }); diff --git a/test/helpers/governance.js b/test/helpers/governance.js index b945a16e0..ae88e151a 100644 --- a/test/helpers/governance.js +++ b/test/helpers/governance.js @@ -1,4 +1,4 @@ -const { time } = require('@openzeppelin/test-helpers'); +const { forward } = require('../helpers/time'); function zip(...args) { return Array(Math.max(...args.map(array => array.length))) @@ -15,8 +15,9 @@ function concatOpts(args, opts = null) { } class GovernorHelper { - constructor(governor) { + constructor(governor, mode = 'blocknumber') { this.governor = governor; + this.mode = mode; } delegate(delegation = {}, opts = null) { @@ -116,21 +117,17 @@ class GovernorHelper { waitForSnapshot(offset = 0) { const proposal = this.currentProposal; - return this.governor - .proposalSnapshot(proposal.id) - .then(blockNumber => time.advanceBlockTo(blockNumber.addn(offset))); + return this.governor.proposalSnapshot(proposal.id).then(timepoint => forward[this.mode](timepoint.addn(offset))); } waitForDeadline(offset = 0) { const proposal = this.currentProposal; - return this.governor - .proposalDeadline(proposal.id) - .then(blockNumber => time.advanceBlockTo(blockNumber.addn(offset))); + return this.governor.proposalDeadline(proposal.id).then(timepoint => forward[this.mode](timepoint.addn(offset))); } waitForEta(offset = 0) { const proposal = this.currentProposal; - return this.governor.proposalEta(proposal.id).then(timestamp => time.increaseTo(timestamp.addn(offset))); + return this.governor.proposalEta(proposal.id).then(timestamp => forward.timestamp(timestamp.addn(offset))); } /** diff --git a/test/helpers/time.js b/test/helpers/time.js new file mode 100644 index 000000000..2e5f6d85a --- /dev/null +++ b/test/helpers/time.js @@ -0,0 +1,16 @@ +const { time } = require('@openzeppelin/test-helpers'); + +module.exports = { + clock: { + blocknumber: () => web3.eth.getBlock('latest').then(block => block.number), + timestamp: () => web3.eth.getBlock('latest').then(block => block.timestamp), + }, + clockFromReceipt: { + blocknumber: receipt => Promise.resolve(receipt.blockNumber), + timestamp: receipt => web3.eth.getBlock(receipt.blockNumber).then(block => block.timestamp), + }, + forward: { + blocknumber: time.advanceBlockTo, + timestamp: time.increaseTo, + }, +}; diff --git a/test/token/ERC20/extensions/ERC20Votes.test.js b/test/token/ERC20/extensions/ERC20Votes.test.js index 9759c1162..e722ed1a1 100644 --- a/test/token/ERC20/extensions/ERC20Votes.test.js +++ b/test/token/ERC20/extensions/ERC20Votes.test.js @@ -8,11 +8,11 @@ const { fromRpcSig } = require('ethereumjs-util'); const ethSigUtil = require('eth-sig-util'); const Wallet = require('ethereumjs-wallet').default; -const ERC20Votes = artifacts.require('$ERC20Votes'); - const { batchInBlock } = require('../../../helpers/txpool'); const { getDomain, domainType, domainSeparator } = require('../../../helpers/eip712'); -const { getChainId } = require('../../../helpers/chainid'); +const { clock, clockFromReceipt } = require('../../../helpers/time'); + +const { shouldBehaveLikeEIP6372 } = require('../../../governance/utils/EIP6372.behavior'); const Delegation = [ { name: 'delegatee', type: 'address' }, @@ -20,541 +20,559 @@ const Delegation = [ { name: 'expiry', type: 'uint256' }, ]; +const MODES = { + blocknumber: artifacts.require('$ERC20Votes'), + timestamp: artifacts.require('$ERC20VotesTimestampMock'), +}; + contract('ERC20Votes', function (accounts) { const [holder, recipient, holderDelegatee, other1, other2] = accounts; const name = 'My Token'; const symbol = 'MTKN'; - const version = '1'; const supply = new BN('10000000000000000000000000'); - beforeEach(async function () { - this.chainId = await getChainId(); - this.token = await ERC20Votes.new(name, symbol, name); - }); - - it('initial nonce is 0', async function () { - expect(await this.token.nonces(holder)).to.be.bignumber.equal('0'); - }); - - it('domain separator', async function () { - expect(await this.token.DOMAIN_SEPARATOR()).to.equal(await getDomain(this.token).then(domainSeparator)); - }); - - it('minting restriction', async function () { - const amount = new BN('2').pow(new BN('224')); - await expectRevert(this.token.$_mint(holder, amount), 'ERC20Votes: total supply risks overflowing votes'); - }); - - it('recent checkpoints', async function () { - await this.token.delegate(holder, { from: holder }); - for (let i = 0; i < 6; i++) { - await this.token.$_mint(holder, 1); - } - const block = await web3.eth.getBlockNumber(); - expect(await this.token.numCheckpoints(holder)).to.be.bignumber.equal('6'); - // recent - expect(await this.token.getPastVotes(holder, block - 1)).to.be.bignumber.equal('5'); - // non-recent - expect(await this.token.getPastVotes(holder, block - 6)).to.be.bignumber.equal('0'); - }); - - describe('set delegation', function () { - describe('call', function () { - it('delegation with balance', async function () { - await this.token.$_mint(holder, supply); - expect(await this.token.delegates(holder)).to.be.equal(ZERO_ADDRESS); - - const { receipt } = await this.token.delegate(holder, { from: holder }); - expectEvent(receipt, 'DelegateChanged', { - delegator: holder, - fromDelegate: ZERO_ADDRESS, - toDelegate: holder, - }); - expectEvent(receipt, 'DelegateVotesChanged', { - delegate: holder, - previousBalance: '0', - newBalance: supply, - }); - - expect(await this.token.delegates(holder)).to.be.equal(holder); - - expect(await this.token.getVotes(holder)).to.be.bignumber.equal(supply); - expect(await this.token.getPastVotes(holder, receipt.blockNumber - 1)).to.be.bignumber.equal('0'); - await time.advanceBlock(); - expect(await this.token.getPastVotes(holder, receipt.blockNumber)).to.be.bignumber.equal(supply); - }); - - it('delegation without balance', async function () { - expect(await this.token.delegates(holder)).to.be.equal(ZERO_ADDRESS); - - const { receipt } = await this.token.delegate(holder, { from: holder }); - expectEvent(receipt, 'DelegateChanged', { - delegator: holder, - fromDelegate: ZERO_ADDRESS, - toDelegate: holder, - }); - expectEvent.notEmitted(receipt, 'DelegateVotesChanged'); - - expect(await this.token.delegates(holder)).to.be.equal(holder); - }); - }); - - describe('with signature', function () { - const delegator = Wallet.generate(); - const delegatorAddress = web3.utils.toChecksumAddress(delegator.getAddressString()); - const nonce = 0; - - const buildData = (contract, message) => - getDomain(contract).then(domain => ({ - primaryType: 'Delegation', - types: { EIP712Domain: domainType(domain), Delegation }, - domain, - message, - })); - + for (const [mode, artifact] of Object.entries(MODES)) { + describe(`vote with ${mode}`, function () { beforeEach(async function () { - await this.token.$_mint(delegatorAddress, supply); + this.token = await artifact.new(name, symbol, name); }); - it('accept signed delegation', async function () { - const { v, r, s } = await buildData(this.token, { - delegatee: delegatorAddress, - nonce, - expiry: MAX_UINT256, - }) - .then(data => ethSigUtil.signTypedMessage(delegator.getPrivateKey(), { data })) - .then(fromRpcSig); + shouldBehaveLikeEIP6372(mode); - expect(await this.token.delegates(delegatorAddress)).to.be.equal(ZERO_ADDRESS); + it('initial nonce is 0', async function () { + expect(await this.token.nonces(holder)).to.be.bignumber.equal('0'); + }); - const { receipt } = await this.token.delegateBySig(delegatorAddress, nonce, MAX_UINT256, v, r, s); - expectEvent(receipt, 'DelegateChanged', { - delegator: delegatorAddress, - fromDelegate: ZERO_ADDRESS, - toDelegate: delegatorAddress, - }); - expectEvent(receipt, 'DelegateVotesChanged', { - delegate: delegatorAddress, - previousBalance: '0', - newBalance: supply, + it('domain separator', async function () { + expect(await this.token.DOMAIN_SEPARATOR()).to.equal(await getDomain(this.token).then(domainSeparator)); + }); + + it('minting restriction', async function () { + const amount = new BN('2').pow(new BN('224')); + await expectRevert(this.token.$_mint(holder, amount), 'ERC20Votes: total supply risks overflowing votes'); + }); + + it('recent checkpoints', async function () { + await this.token.delegate(holder, { from: holder }); + for (let i = 0; i < 6; i++) { + await this.token.$_mint(holder, 1); + } + const block = await clock[mode](); + expect(await this.token.numCheckpoints(holder)).to.be.bignumber.equal('6'); + // recent + expect(await this.token.getPastVotes(holder, block - 1)).to.be.bignumber.equal('5'); + // non-recent + expect(await this.token.getPastVotes(holder, block - 6)).to.be.bignumber.equal('0'); + }); + + describe('set delegation', function () { + describe('call', function () { + it('delegation with balance', async function () { + await this.token.$_mint(holder, supply); + expect(await this.token.delegates(holder)).to.be.equal(ZERO_ADDRESS); + + const { receipt } = await this.token.delegate(holder, { from: holder }); + const timepoint = await clockFromReceipt[mode](receipt); + + expectEvent(receipt, 'DelegateChanged', { + delegator: holder, + fromDelegate: ZERO_ADDRESS, + toDelegate: holder, + }); + expectEvent(receipt, 'DelegateVotesChanged', { + delegate: holder, + previousBalance: '0', + newBalance: supply, + }); + + expect(await this.token.delegates(holder)).to.be.equal(holder); + + expect(await this.token.getVotes(holder)).to.be.bignumber.equal(supply); + expect(await this.token.getPastVotes(holder, timepoint - 1)).to.be.bignumber.equal('0'); + await time.advanceBlock(); + expect(await this.token.getPastVotes(holder, timepoint)).to.be.bignumber.equal(supply); + }); + + it('delegation without balance', async function () { + expect(await this.token.delegates(holder)).to.be.equal(ZERO_ADDRESS); + + const { receipt } = await this.token.delegate(holder, { from: holder }); + expectEvent(receipt, 'DelegateChanged', { + delegator: holder, + fromDelegate: ZERO_ADDRESS, + toDelegate: holder, + }); + expectEvent.notEmitted(receipt, 'DelegateVotesChanged'); + + expect(await this.token.delegates(holder)).to.be.equal(holder); + }); }); - expect(await this.token.delegates(delegatorAddress)).to.be.equal(delegatorAddress); + describe('with signature', function () { + const delegator = Wallet.generate(); + const delegatorAddress = web3.utils.toChecksumAddress(delegator.getAddressString()); + const nonce = 0; - expect(await this.token.getVotes(delegatorAddress)).to.be.bignumber.equal(supply); - expect(await this.token.getPastVotes(delegatorAddress, receipt.blockNumber - 1)).to.be.bignumber.equal('0'); - await time.advanceBlock(); - expect(await this.token.getPastVotes(delegatorAddress, receipt.blockNumber)).to.be.bignumber.equal(supply); + const buildData = (contract, message) => + getDomain(contract).then(domain => ({ + primaryType: 'Delegation', + types: { EIP712Domain: domainType(domain), Delegation }, + domain, + message, + })); + + beforeEach(async function () { + await this.token.$_mint(delegatorAddress, supply); + }); + + it('accept signed delegation', async function () { + const { v, r, s } = await buildData(this.token, { + delegatee: delegatorAddress, + nonce, + expiry: MAX_UINT256, + }).then(data => fromRpcSig(ethSigUtil.signTypedMessage(delegator.getPrivateKey(), { data }))); + + expect(await this.token.delegates(delegatorAddress)).to.be.equal(ZERO_ADDRESS); + + const { receipt } = await this.token.delegateBySig(delegatorAddress, nonce, MAX_UINT256, v, r, s); + const timepoint = await clockFromReceipt[mode](receipt); + + expectEvent(receipt, 'DelegateChanged', { + delegator: delegatorAddress, + fromDelegate: ZERO_ADDRESS, + toDelegate: delegatorAddress, + }); + expectEvent(receipt, 'DelegateVotesChanged', { + delegate: delegatorAddress, + previousBalance: '0', + newBalance: supply, + }); + + expect(await this.token.delegates(delegatorAddress)).to.be.equal(delegatorAddress); + + expect(await this.token.getVotes(delegatorAddress)).to.be.bignumber.equal(supply); + expect(await this.token.getPastVotes(delegatorAddress, timepoint - 1)).to.be.bignumber.equal('0'); + await time.advanceBlock(); + expect(await this.token.getPastVotes(delegatorAddress, timepoint)).to.be.bignumber.equal(supply); + }); + + it('rejects reused signature', async function () { + const { v, r, s } = await buildData(this.token, { + delegatee: delegatorAddress, + nonce, + expiry: MAX_UINT256, + }).then(data => fromRpcSig(ethSigUtil.signTypedMessage(delegator.getPrivateKey(), { data }))); + + await this.token.delegateBySig(delegatorAddress, nonce, MAX_UINT256, v, r, s); + + await expectRevert( + this.token.delegateBySig(delegatorAddress, nonce, MAX_UINT256, v, r, s), + 'ERC20Votes: invalid nonce', + ); + }); + + it('rejects bad delegatee', async function () { + const { v, r, s } = await buildData(this.token, { + delegatee: delegatorAddress, + nonce, + expiry: MAX_UINT256, + }).then(data => fromRpcSig(ethSigUtil.signTypedMessage(delegator.getPrivateKey(), { data }))); + + const receipt = await this.token.delegateBySig(holderDelegatee, nonce, MAX_UINT256, v, r, s); + const { args } = receipt.logs.find(({ event }) => event == 'DelegateChanged'); + expect(args.delegator).to.not.be.equal(delegatorAddress); + expect(args.fromDelegate).to.be.equal(ZERO_ADDRESS); + expect(args.toDelegate).to.be.equal(holderDelegatee); + }); + + it('rejects bad nonce', async function () { + const { v, r, s } = await buildData(this.token, { + delegatee: delegatorAddress, + nonce, + expiry: MAX_UINT256, + }).then(data => fromRpcSig(ethSigUtil.signTypedMessage(delegator.getPrivateKey(), { data }))); + + await expectRevert( + this.token.delegateBySig(delegatorAddress, nonce + 1, MAX_UINT256, v, r, s), + 'ERC20Votes: invalid nonce', + ); + }); + + it('rejects expired permit', async function () { + const expiry = (await time.latest()) - time.duration.weeks(1); + const { v, r, s } = await buildData(this.token, { + delegatee: delegatorAddress, + nonce, + expiry, + }).then(data => fromRpcSig(ethSigUtil.signTypedMessage(delegator.getPrivateKey(), { data }))); + + await expectRevert( + this.token.delegateBySig(delegatorAddress, nonce, expiry, v, r, s), + 'ERC20Votes: signature expired', + ); + }); + }); }); - it('rejects reused signature', async function () { - const { v, r, s } = await buildData(this.token, { - delegatee: delegatorAddress, - nonce, - expiry: MAX_UINT256, - }) - .then(data => ethSigUtil.signTypedMessage(delegator.getPrivateKey(), { data })) - .then(fromRpcSig); + describe('change delegation', function () { + beforeEach(async function () { + await this.token.$_mint(holder, supply); + await this.token.delegate(holder, { from: holder }); + }); - await this.token.delegateBySig(delegatorAddress, nonce, MAX_UINT256, v, r, s); + it('call', async function () { + expect(await this.token.delegates(holder)).to.be.equal(holder); - await expectRevert( - this.token.delegateBySig(delegatorAddress, nonce, MAX_UINT256, v, r, s), - 'ERC20Votes: invalid nonce', - ); + const { receipt } = await this.token.delegate(holderDelegatee, { from: holder }); + const timepoint = await clockFromReceipt[mode](receipt); + + expectEvent(receipt, 'DelegateChanged', { + delegator: holder, + fromDelegate: holder, + toDelegate: holderDelegatee, + }); + expectEvent(receipt, 'DelegateVotesChanged', { + delegate: holder, + previousBalance: supply, + newBalance: '0', + }); + expectEvent(receipt, 'DelegateVotesChanged', { + delegate: holderDelegatee, + previousBalance: '0', + newBalance: supply, + }); + + expect(await this.token.delegates(holder)).to.be.equal(holderDelegatee); + + expect(await this.token.getVotes(holder)).to.be.bignumber.equal('0'); + expect(await this.token.getVotes(holderDelegatee)).to.be.bignumber.equal(supply); + expect(await this.token.getPastVotes(holder, timepoint - 1)).to.be.bignumber.equal(supply); + expect(await this.token.getPastVotes(holderDelegatee, timepoint - 1)).to.be.bignumber.equal('0'); + await time.advanceBlock(); + expect(await this.token.getPastVotes(holder, timepoint)).to.be.bignumber.equal('0'); + expect(await this.token.getPastVotes(holderDelegatee, timepoint)).to.be.bignumber.equal(supply); + }); }); - it('rejects bad delegatee', async function () { - const { v, r, s } = await buildData(this.token, { - delegatee: delegatorAddress, - nonce, - expiry: MAX_UINT256, - }) - .then(data => ethSigUtil.signTypedMessage(delegator.getPrivateKey(), { data })) - .then(fromRpcSig); + describe('transfers', function () { + beforeEach(async function () { + await this.token.$_mint(holder, supply); + }); - const receipt = await this.token.delegateBySig(holderDelegatee, nonce, MAX_UINT256, v, r, s); - const { args } = receipt.logs.find(({ event }) => event == 'DelegateChanged'); - expect(args.delegator).to.not.be.equal(delegatorAddress); - expect(args.fromDelegate).to.be.equal(ZERO_ADDRESS); - expect(args.toDelegate).to.be.equal(holderDelegatee); + it('no delegation', async function () { + const { receipt } = await this.token.transfer(recipient, 1, { from: holder }); + expectEvent(receipt, 'Transfer', { from: holder, to: recipient, value: '1' }); + expectEvent.notEmitted(receipt, 'DelegateVotesChanged'); + + this.holderVotes = '0'; + this.recipientVotes = '0'; + }); + + it('sender delegation', async function () { + await this.token.delegate(holder, { from: holder }); + + const { receipt } = await this.token.transfer(recipient, 1, { from: holder }); + expectEvent(receipt, 'Transfer', { from: holder, to: recipient, value: '1' }); + expectEvent(receipt, 'DelegateVotesChanged', { + delegate: holder, + previousBalance: supply, + newBalance: supply.subn(1), + }); + + const { logIndex: transferLogIndex } = receipt.logs.find(({ event }) => event == 'Transfer'); + expect( + receipt.logs + .filter(({ event }) => event == 'DelegateVotesChanged') + .every(({ logIndex }) => transferLogIndex < logIndex), + ).to.be.equal(true); + + this.holderVotes = supply.subn(1); + this.recipientVotes = '0'; + }); + + it('receiver delegation', async function () { + await this.token.delegate(recipient, { from: recipient }); + + const { receipt } = await this.token.transfer(recipient, 1, { from: holder }); + expectEvent(receipt, 'Transfer', { from: holder, to: recipient, value: '1' }); + expectEvent(receipt, 'DelegateVotesChanged', { delegate: recipient, previousBalance: '0', newBalance: '1' }); + + const { logIndex: transferLogIndex } = receipt.logs.find(({ event }) => event == 'Transfer'); + expect( + receipt.logs + .filter(({ event }) => event == 'DelegateVotesChanged') + .every(({ logIndex }) => transferLogIndex < logIndex), + ).to.be.equal(true); + + this.holderVotes = '0'; + this.recipientVotes = '1'; + }); + + it('full delegation', async function () { + await this.token.delegate(holder, { from: holder }); + await this.token.delegate(recipient, { from: recipient }); + + const { receipt } = await this.token.transfer(recipient, 1, { from: holder }); + expectEvent(receipt, 'Transfer', { from: holder, to: recipient, value: '1' }); + expectEvent(receipt, 'DelegateVotesChanged', { + delegate: holder, + previousBalance: supply, + newBalance: supply.subn(1), + }); + expectEvent(receipt, 'DelegateVotesChanged', { delegate: recipient, previousBalance: '0', newBalance: '1' }); + + const { logIndex: transferLogIndex } = receipt.logs.find(({ event }) => event == 'Transfer'); + expect( + receipt.logs + .filter(({ event }) => event == 'DelegateVotesChanged') + .every(({ logIndex }) => transferLogIndex < logIndex), + ).to.be.equal(true); + + this.holderVotes = supply.subn(1); + this.recipientVotes = '1'; + }); + + afterEach(async function () { + expect(await this.token.getVotes(holder)).to.be.bignumber.equal(this.holderVotes); + expect(await this.token.getVotes(recipient)).to.be.bignumber.equal(this.recipientVotes); + + // need to advance 2 blocks to see the effect of a transfer on "getPastVotes" + const timepoint = await clock[mode](); + await time.advanceBlock(); + expect(await this.token.getPastVotes(holder, timepoint)).to.be.bignumber.equal(this.holderVotes); + expect(await this.token.getPastVotes(recipient, timepoint)).to.be.bignumber.equal(this.recipientVotes); + }); }); - it('rejects bad nonce', async function () { - const { v, r, s } = await buildData(this.token, { - delegatee: delegatorAddress, - nonce, - expiry: MAX_UINT256, - }) - .then(data => ethSigUtil.signTypedMessage(delegator.getPrivateKey(), { data })) - .then(fromRpcSig); + // The following tests are a adaptation of https://github.com/compound-finance/compound-protocol/blob/master/tests/Governance/CompTest.js. + describe('Compound test suite', function () { + beforeEach(async function () { + await this.token.$_mint(holder, supply); + }); - await expectRevert( - this.token.delegateBySig(delegatorAddress, nonce + 1, MAX_UINT256, v, r, s), - 'ERC20Votes: invalid nonce', - ); + describe('balanceOf', function () { + it('grants to initial account', async function () { + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal('10000000000000000000000000'); + }); + }); + + describe('numCheckpoints', function () { + it('returns the number of checkpoints for a delegate', async function () { + await this.token.transfer(recipient, '100', { from: holder }); //give an account a few tokens for readability + expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('0'); + + const t1 = await this.token.delegate(other1, { from: recipient }); + t1.timepoint = await clockFromReceipt[mode](t1.receipt); + expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('1'); + + const t2 = await this.token.transfer(other2, 10, { from: recipient }); + t2.timepoint = await clockFromReceipt[mode](t2.receipt); + expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('2'); + + const t3 = await this.token.transfer(other2, 10, { from: recipient }); + t3.timepoint = await clockFromReceipt[mode](t3.receipt); + expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('3'); + + const t4 = await this.token.transfer(recipient, 20, { from: holder }); + t4.timepoint = await clockFromReceipt[mode](t4.receipt); + expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('4'); + + expect(await this.token.checkpoints(other1, 0)).to.be.deep.equal([t1.timepoint.toString(), '100']); + expect(await this.token.checkpoints(other1, 1)).to.be.deep.equal([t2.timepoint.toString(), '90']); + expect(await this.token.checkpoints(other1, 2)).to.be.deep.equal([t3.timepoint.toString(), '80']); + expect(await this.token.checkpoints(other1, 3)).to.be.deep.equal([t4.timepoint.toString(), '100']); + + await time.advanceBlock(); + expect(await this.token.getPastVotes(other1, t1.timepoint)).to.be.bignumber.equal('100'); + expect(await this.token.getPastVotes(other1, t2.timepoint)).to.be.bignumber.equal('90'); + expect(await this.token.getPastVotes(other1, t3.timepoint)).to.be.bignumber.equal('80'); + expect(await this.token.getPastVotes(other1, t4.timepoint)).to.be.bignumber.equal('100'); + }); + + it('does not add more than one checkpoint in a block', async function () { + await this.token.transfer(recipient, '100', { from: holder }); + expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('0'); + + const [t1, t2, t3] = await batchInBlock([ + () => this.token.delegate(other1, { from: recipient, gas: 100000 }), + () => this.token.transfer(other2, 10, { from: recipient, gas: 100000 }), + () => this.token.transfer(other2, 10, { from: recipient, gas: 100000 }), + ]); + t1.timepoint = await clockFromReceipt[mode](t1.receipt); + t2.timepoint = await clockFromReceipt[mode](t2.receipt); + t3.timepoint = await clockFromReceipt[mode](t3.receipt); + + expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('1'); + expect(await this.token.checkpoints(other1, 0)).to.be.deep.equal([t1.timepoint.toString(), '80']); + + const t4 = await this.token.transfer(recipient, 20, { from: holder }); + t4.timepoint = await clockFromReceipt[mode](t4.receipt); + + expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('2'); + expect(await this.token.checkpoints(other1, 1)).to.be.deep.equal([t4.timepoint.toString(), '100']); + }); + }); + + describe('getPastVotes', function () { + it('reverts if block number >= current block', async function () { + await expectRevert(this.token.getPastVotes(other1, 5e10), 'ERC20Votes: future lookup'); + }); + + it('returns 0 if there are no checkpoints', async function () { + expect(await this.token.getPastVotes(other1, 0)).to.be.bignumber.equal('0'); + }); + + it('returns the latest block if >= last checkpoint block', async function () { + const { receipt } = await this.token.delegate(other1, { from: holder }); + const timepoint = await clockFromReceipt[mode](receipt); + await time.advanceBlock(); + await time.advanceBlock(); + + expect(await this.token.getPastVotes(other1, timepoint)).to.be.bignumber.equal( + '10000000000000000000000000', + ); + expect(await this.token.getPastVotes(other1, timepoint + 1)).to.be.bignumber.equal( + '10000000000000000000000000', + ); + }); + + it('returns zero if < first checkpoint block', async function () { + await time.advanceBlock(); + const { receipt } = await this.token.delegate(other1, { from: holder }); + const timepoint = await clockFromReceipt[mode](receipt); + await time.advanceBlock(); + await time.advanceBlock(); + + expect(await this.token.getPastVotes(other1, timepoint - 1)).to.be.bignumber.equal('0'); + expect(await this.token.getPastVotes(other1, timepoint + 1)).to.be.bignumber.equal( + '10000000000000000000000000', + ); + }); + + it('generally returns the voting balance at the appropriate checkpoint', async function () { + const t1 = await this.token.delegate(other1, { from: holder }); + await time.advanceBlock(); + await time.advanceBlock(); + const t2 = await this.token.transfer(other2, 10, { from: holder }); + await time.advanceBlock(); + await time.advanceBlock(); + const t3 = await this.token.transfer(other2, 10, { from: holder }); + await time.advanceBlock(); + await time.advanceBlock(); + const t4 = await this.token.transfer(holder, 20, { from: other2 }); + await time.advanceBlock(); + await time.advanceBlock(); + + t1.timepoint = await clockFromReceipt[mode](t1.receipt); + t2.timepoint = await clockFromReceipt[mode](t2.receipt); + t3.timepoint = await clockFromReceipt[mode](t3.receipt); + t4.timepoint = await clockFromReceipt[mode](t4.receipt); + + expect(await this.token.getPastVotes(other1, t1.timepoint - 1)).to.be.bignumber.equal('0'); + expect(await this.token.getPastVotes(other1, t1.timepoint)).to.be.bignumber.equal( + '10000000000000000000000000', + ); + expect(await this.token.getPastVotes(other1, t1.timepoint + 1)).to.be.bignumber.equal( + '10000000000000000000000000', + ); + expect(await this.token.getPastVotes(other1, t2.timepoint)).to.be.bignumber.equal( + '9999999999999999999999990', + ); + expect(await this.token.getPastVotes(other1, t2.timepoint + 1)).to.be.bignumber.equal( + '9999999999999999999999990', + ); + expect(await this.token.getPastVotes(other1, t3.timepoint)).to.be.bignumber.equal( + '9999999999999999999999980', + ); + expect(await this.token.getPastVotes(other1, t3.timepoint + 1)).to.be.bignumber.equal( + '9999999999999999999999980', + ); + expect(await this.token.getPastVotes(other1, t4.timepoint)).to.be.bignumber.equal( + '10000000000000000000000000', + ); + expect(await this.token.getPastVotes(other1, t4.timepoint + 1)).to.be.bignumber.equal( + '10000000000000000000000000', + ); + }); + }); }); - it('rejects expired permit', async function () { - const expiry = (await time.latest()) - time.duration.weeks(1); + describe('getPastTotalSupply', function () { + beforeEach(async function () { + await this.token.delegate(holder, { from: holder }); + }); - const { v, r, s } = await buildData(this.token, { - delegatee: delegatorAddress, - nonce, - expiry, - }) - .then(data => ethSigUtil.signTypedMessage(delegator.getPrivateKey(), { data })) - .then(fromRpcSig); + it('reverts if block number >= current block', async function () { + await expectRevert(this.token.getPastTotalSupply(5e10), 'ERC20Votes: future lookup'); + }); - await expectRevert( - this.token.delegateBySig(delegatorAddress, nonce, expiry, v, r, s), - 'ERC20Votes: signature expired', - ); + it('returns 0 if there are no checkpoints', async function () { + expect(await this.token.getPastTotalSupply(0)).to.be.bignumber.equal('0'); + }); + + it('returns the latest block if >= last checkpoint block', async function () { + const { receipt } = await this.token.$_mint(holder, supply); + const timepoint = await clockFromReceipt[mode](receipt); + + await time.advanceBlock(); + await time.advanceBlock(); + + expect(await this.token.getPastTotalSupply(timepoint)).to.be.bignumber.equal(supply); + expect(await this.token.getPastTotalSupply(timepoint + 1)).to.be.bignumber.equal(supply); + }); + + it('returns zero if < first checkpoint block', async function () { + await time.advanceBlock(); + const { receipt } = await this.token.$_mint(holder, supply); + const timepoint = await clockFromReceipt[mode](receipt); + await time.advanceBlock(); + await time.advanceBlock(); + + expect(await this.token.getPastTotalSupply(timepoint - 1)).to.be.bignumber.equal('0'); + expect(await this.token.getPastTotalSupply(timepoint + 1)).to.be.bignumber.equal( + '10000000000000000000000000', + ); + }); + + it('generally returns the voting balance at the appropriate checkpoint', async function () { + const t1 = await this.token.$_mint(holder, supply); + await time.advanceBlock(); + await time.advanceBlock(); + const t2 = await this.token.$_burn(holder, 10); + await time.advanceBlock(); + await time.advanceBlock(); + const t3 = await this.token.$_burn(holder, 10); + await time.advanceBlock(); + await time.advanceBlock(); + const t4 = await this.token.$_mint(holder, 20); + await time.advanceBlock(); + await time.advanceBlock(); + + t1.timepoint = await clockFromReceipt[mode](t1.receipt); + t2.timepoint = await clockFromReceipt[mode](t2.receipt); + t3.timepoint = await clockFromReceipt[mode](t3.receipt); + t4.timepoint = await clockFromReceipt[mode](t4.receipt); + + expect(await this.token.getPastTotalSupply(t1.timepoint - 1)).to.be.bignumber.equal('0'); + expect(await this.token.getPastTotalSupply(t1.timepoint)).to.be.bignumber.equal('10000000000000000000000000'); + expect(await this.token.getPastTotalSupply(t1.timepoint + 1)).to.be.bignumber.equal( + '10000000000000000000000000', + ); + expect(await this.token.getPastTotalSupply(t2.timepoint)).to.be.bignumber.equal('9999999999999999999999990'); + expect(await this.token.getPastTotalSupply(t2.timepoint + 1)).to.be.bignumber.equal( + '9999999999999999999999990', + ); + expect(await this.token.getPastTotalSupply(t3.timepoint)).to.be.bignumber.equal('9999999999999999999999980'); + expect(await this.token.getPastTotalSupply(t3.timepoint + 1)).to.be.bignumber.equal( + '9999999999999999999999980', + ); + expect(await this.token.getPastTotalSupply(t4.timepoint)).to.be.bignumber.equal('10000000000000000000000000'); + expect(await this.token.getPastTotalSupply(t4.timepoint + 1)).to.be.bignumber.equal( + '10000000000000000000000000', + ); + }); }); }); - }); - - describe('change delegation', function () { - beforeEach(async function () { - await this.token.$_mint(holder, supply); - await this.token.delegate(holder, { from: holder }); - }); - - it('call', async function () { - expect(await this.token.delegates(holder)).to.be.equal(holder); - - const { receipt } = await this.token.delegate(holderDelegatee, { from: holder }); - expectEvent(receipt, 'DelegateChanged', { - delegator: holder, - fromDelegate: holder, - toDelegate: holderDelegatee, - }); - expectEvent(receipt, 'DelegateVotesChanged', { - delegate: holder, - previousBalance: supply, - newBalance: '0', - }); - expectEvent(receipt, 'DelegateVotesChanged', { - delegate: holderDelegatee, - previousBalance: '0', - newBalance: supply, - }); - - expect(await this.token.delegates(holder)).to.be.equal(holderDelegatee); - - expect(await this.token.getVotes(holder)).to.be.bignumber.equal('0'); - expect(await this.token.getVotes(holderDelegatee)).to.be.bignumber.equal(supply); - expect(await this.token.getPastVotes(holder, receipt.blockNumber - 1)).to.be.bignumber.equal(supply); - expect(await this.token.getPastVotes(holderDelegatee, receipt.blockNumber - 1)).to.be.bignumber.equal('0'); - await time.advanceBlock(); - expect(await this.token.getPastVotes(holder, receipt.blockNumber)).to.be.bignumber.equal('0'); - expect(await this.token.getPastVotes(holderDelegatee, receipt.blockNumber)).to.be.bignumber.equal(supply); - }); - }); - - describe('transfers', function () { - beforeEach(async function () { - await this.token.$_mint(holder, supply); - }); - - it('no delegation', async function () { - const { receipt } = await this.token.transfer(recipient, 1, { from: holder }); - expectEvent(receipt, 'Transfer', { from: holder, to: recipient, value: '1' }); - expectEvent.notEmitted(receipt, 'DelegateVotesChanged'); - - this.holderVotes = '0'; - this.recipientVotes = '0'; - }); - - it('sender delegation', async function () { - await this.token.delegate(holder, { from: holder }); - - const { receipt } = await this.token.transfer(recipient, 1, { from: holder }); - expectEvent(receipt, 'Transfer', { from: holder, to: recipient, value: '1' }); - expectEvent(receipt, 'DelegateVotesChanged', { - delegate: holder, - previousBalance: supply, - newBalance: supply.subn(1), - }); - - const { logIndex: transferLogIndex } = receipt.logs.find(({ event }) => event == 'Transfer'); - expect( - receipt.logs - .filter(({ event }) => event == 'DelegateVotesChanged') - .every(({ logIndex }) => transferLogIndex < logIndex), - ).to.be.equal(true); - - this.holderVotes = supply.subn(1); - this.recipientVotes = '0'; - }); - - it('receiver delegation', async function () { - await this.token.delegate(recipient, { from: recipient }); - - const { receipt } = await this.token.transfer(recipient, 1, { from: holder }); - expectEvent(receipt, 'Transfer', { from: holder, to: recipient, value: '1' }); - expectEvent(receipt, 'DelegateVotesChanged', { delegate: recipient, previousBalance: '0', newBalance: '1' }); - - const { logIndex: transferLogIndex } = receipt.logs.find(({ event }) => event == 'Transfer'); - expect( - receipt.logs - .filter(({ event }) => event == 'DelegateVotesChanged') - .every(({ logIndex }) => transferLogIndex < logIndex), - ).to.be.equal(true); - - this.holderVotes = '0'; - this.recipientVotes = '1'; - }); - - it('full delegation', async function () { - await this.token.delegate(holder, { from: holder }); - await this.token.delegate(recipient, { from: recipient }); - - const { receipt } = await this.token.transfer(recipient, 1, { from: holder }); - expectEvent(receipt, 'Transfer', { from: holder, to: recipient, value: '1' }); - expectEvent(receipt, 'DelegateVotesChanged', { - delegate: holder, - previousBalance: supply, - newBalance: supply.subn(1), - }); - expectEvent(receipt, 'DelegateVotesChanged', { delegate: recipient, previousBalance: '0', newBalance: '1' }); - - const { logIndex: transferLogIndex } = receipt.logs.find(({ event }) => event == 'Transfer'); - expect( - receipt.logs - .filter(({ event }) => event == 'DelegateVotesChanged') - .every(({ logIndex }) => transferLogIndex < logIndex), - ).to.be.equal(true); - - this.holderVotes = supply.subn(1); - this.recipientVotes = '1'; - }); - - afterEach(async function () { - expect(await this.token.getVotes(holder)).to.be.bignumber.equal(this.holderVotes); - expect(await this.token.getVotes(recipient)).to.be.bignumber.equal(this.recipientVotes); - - // need to advance 2 blocks to see the effect of a transfer on "getPastVotes" - const blockNumber = await time.latestBlock(); - await time.advanceBlock(); - expect(await this.token.getPastVotes(holder, blockNumber)).to.be.bignumber.equal(this.holderVotes); - expect(await this.token.getPastVotes(recipient, blockNumber)).to.be.bignumber.equal(this.recipientVotes); - }); - }); - - // The following tests are a adaptation of https://github.com/compound-finance/compound-protocol/blob/master/tests/Governance/CompTest.js. - describe('Compound test suite', function () { - beforeEach(async function () { - await this.token.$_mint(holder, supply); - }); - - describe('balanceOf', function () { - it('grants to initial account', async function () { - expect(await this.token.balanceOf(holder)).to.be.bignumber.equal('10000000000000000000000000'); - }); - }); - - describe('numCheckpoints', function () { - it('returns the number of checkpoints for a delegate', async function () { - await this.token.transfer(recipient, '100', { from: holder }); //give an account a few tokens for readability - expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('0'); - - const t1 = await this.token.delegate(other1, { from: recipient }); - expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('1'); - - const t2 = await this.token.transfer(other2, 10, { from: recipient }); - expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('2'); - - const t3 = await this.token.transfer(other2, 10, { from: recipient }); - expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('3'); - - const t4 = await this.token.transfer(recipient, 20, { from: holder }); - expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('4'); - - expect(await this.token.checkpoints(other1, 0)).to.be.deep.equal([t1.receipt.blockNumber.toString(), '100']); - expect(await this.token.checkpoints(other1, 1)).to.be.deep.equal([t2.receipt.blockNumber.toString(), '90']); - expect(await this.token.checkpoints(other1, 2)).to.be.deep.equal([t3.receipt.blockNumber.toString(), '80']); - expect(await this.token.checkpoints(other1, 3)).to.be.deep.equal([t4.receipt.blockNumber.toString(), '100']); - - await time.advanceBlock(); - expect(await this.token.getPastVotes(other1, t1.receipt.blockNumber)).to.be.bignumber.equal('100'); - expect(await this.token.getPastVotes(other1, t2.receipt.blockNumber)).to.be.bignumber.equal('90'); - expect(await this.token.getPastVotes(other1, t3.receipt.blockNumber)).to.be.bignumber.equal('80'); - expect(await this.token.getPastVotes(other1, t4.receipt.blockNumber)).to.be.bignumber.equal('100'); - }); - - it('does not add more than one checkpoint in a block', async function () { - await this.token.transfer(recipient, '100', { from: holder }); - expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('0'); - - const [t1, t2, t3] = await batchInBlock([ - () => this.token.delegate(other1, { from: recipient, gas: 100000 }), - () => this.token.transfer(other2, 10, { from: recipient, gas: 100000 }), - () => this.token.transfer(other2, 10, { from: recipient, gas: 100000 }), - ]); - expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('1'); - expect(await this.token.checkpoints(other1, 0)).to.be.deep.equal([t1.receipt.blockNumber.toString(), '80']); - // expectReve(await this.token.checkpoints(other1, 1)).to.be.deep.equal([ '0', '0' ]); // Reverts due to array overflow check - // expect(await this.token.checkpoints(other1, 2)).to.be.deep.equal([ '0', '0' ]); // Reverts due to array overflow check - - const t4 = await this.token.transfer(recipient, 20, { from: holder }); - expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('2'); - expect(await this.token.checkpoints(other1, 1)).to.be.deep.equal([t4.receipt.blockNumber.toString(), '100']); - }); - }); - - describe('getPastVotes', function () { - it('reverts if block number >= current block', async function () { - await expectRevert(this.token.getPastVotes(other1, 5e10), 'ERC20Votes: block not yet mined'); - }); - - it('returns 0 if there are no checkpoints', async function () { - expect(await this.token.getPastVotes(other1, 0)).to.be.bignumber.equal('0'); - }); - - it('returns the latest block if >= last checkpoint block', async function () { - const t1 = await this.token.delegate(other1, { from: holder }); - await time.advanceBlock(); - await time.advanceBlock(); - - expect(await this.token.getPastVotes(other1, t1.receipt.blockNumber)).to.be.bignumber.equal( - '10000000000000000000000000', - ); - expect(await this.token.getPastVotes(other1, t1.receipt.blockNumber + 1)).to.be.bignumber.equal( - '10000000000000000000000000', - ); - }); - - it('returns zero if < first checkpoint block', async function () { - await time.advanceBlock(); - const t1 = await this.token.delegate(other1, { from: holder }); - await time.advanceBlock(); - await time.advanceBlock(); - - expect(await this.token.getPastVotes(other1, t1.receipt.blockNumber - 1)).to.be.bignumber.equal('0'); - expect(await this.token.getPastVotes(other1, t1.receipt.blockNumber + 1)).to.be.bignumber.equal( - '10000000000000000000000000', - ); - }); - - it('generally returns the voting balance at the appropriate checkpoint', async function () { - const t1 = await this.token.delegate(other1, { from: holder }); - await time.advanceBlock(); - await time.advanceBlock(); - const t2 = await this.token.transfer(other2, 10, { from: holder }); - await time.advanceBlock(); - await time.advanceBlock(); - const t3 = await this.token.transfer(other2, 10, { from: holder }); - await time.advanceBlock(); - await time.advanceBlock(); - const t4 = await this.token.transfer(holder, 20, { from: other2 }); - await time.advanceBlock(); - await time.advanceBlock(); - - expect(await this.token.getPastVotes(other1, t1.receipt.blockNumber - 1)).to.be.bignumber.equal('0'); - expect(await this.token.getPastVotes(other1, t1.receipt.blockNumber)).to.be.bignumber.equal( - '10000000000000000000000000', - ); - expect(await this.token.getPastVotes(other1, t1.receipt.blockNumber + 1)).to.be.bignumber.equal( - '10000000000000000000000000', - ); - expect(await this.token.getPastVotes(other1, t2.receipt.blockNumber)).to.be.bignumber.equal( - '9999999999999999999999990', - ); - expect(await this.token.getPastVotes(other1, t2.receipt.blockNumber + 1)).to.be.bignumber.equal( - '9999999999999999999999990', - ); - expect(await this.token.getPastVotes(other1, t3.receipt.blockNumber)).to.be.bignumber.equal( - '9999999999999999999999980', - ); - expect(await this.token.getPastVotes(other1, t3.receipt.blockNumber + 1)).to.be.bignumber.equal( - '9999999999999999999999980', - ); - expect(await this.token.getPastVotes(other1, t4.receipt.blockNumber)).to.be.bignumber.equal( - '10000000000000000000000000', - ); - expect(await this.token.getPastVotes(other1, t4.receipt.blockNumber + 1)).to.be.bignumber.equal( - '10000000000000000000000000', - ); - }); - }); - }); - - describe('getPastTotalSupply', function () { - beforeEach(async function () { - await this.token.delegate(holder, { from: holder }); - }); - - it('reverts if block number >= current block', async function () { - await expectRevert(this.token.getPastTotalSupply(5e10), 'ERC20Votes: block not yet mined'); - }); - - it('returns 0 if there are no checkpoints', async function () { - expect(await this.token.getPastTotalSupply(0)).to.be.bignumber.equal('0'); - }); - - it('returns the latest block if >= last checkpoint block', async function () { - t1 = await this.token.$_mint(holder, supply); - - await time.advanceBlock(); - await time.advanceBlock(); - - expect(await this.token.getPastTotalSupply(t1.receipt.blockNumber)).to.be.bignumber.equal(supply); - expect(await this.token.getPastTotalSupply(t1.receipt.blockNumber + 1)).to.be.bignumber.equal(supply); - }); - - it('returns zero if < first checkpoint block', async function () { - await time.advanceBlock(); - const t1 = await this.token.$_mint(holder, supply); - await time.advanceBlock(); - await time.advanceBlock(); - - expect(await this.token.getPastTotalSupply(t1.receipt.blockNumber - 1)).to.be.bignumber.equal('0'); - expect(await this.token.getPastTotalSupply(t1.receipt.blockNumber + 1)).to.be.bignumber.equal( - '10000000000000000000000000', - ); - }); - - it('generally returns the voting balance at the appropriate checkpoint', async function () { - const t1 = await this.token.$_mint(holder, supply); - await time.advanceBlock(); - await time.advanceBlock(); - const t2 = await this.token.$_burn(holder, 10); - await time.advanceBlock(); - await time.advanceBlock(); - const t3 = await this.token.$_burn(holder, 10); - await time.advanceBlock(); - await time.advanceBlock(); - const t4 = await this.token.$_mint(holder, 20); - await time.advanceBlock(); - await time.advanceBlock(); - - expect(await this.token.getPastTotalSupply(t1.receipt.blockNumber - 1)).to.be.bignumber.equal('0'); - expect(await this.token.getPastTotalSupply(t1.receipt.blockNumber)).to.be.bignumber.equal( - '10000000000000000000000000', - ); - expect(await this.token.getPastTotalSupply(t1.receipt.blockNumber + 1)).to.be.bignumber.equal( - '10000000000000000000000000', - ); - expect(await this.token.getPastTotalSupply(t2.receipt.blockNumber)).to.be.bignumber.equal( - '9999999999999999999999990', - ); - expect(await this.token.getPastTotalSupply(t2.receipt.blockNumber + 1)).to.be.bignumber.equal( - '9999999999999999999999990', - ); - expect(await this.token.getPastTotalSupply(t3.receipt.blockNumber)).to.be.bignumber.equal( - '9999999999999999999999980', - ); - expect(await this.token.getPastTotalSupply(t3.receipt.blockNumber + 1)).to.be.bignumber.equal( - '9999999999999999999999980', - ); - expect(await this.token.getPastTotalSupply(t4.receipt.blockNumber)).to.be.bignumber.equal( - '10000000000000000000000000', - ); - expect(await this.token.getPastTotalSupply(t4.receipt.blockNumber + 1)).to.be.bignumber.equal( - '10000000000000000000000000', - ); - }); - }); + } }); diff --git a/test/token/ERC20/extensions/ERC20VotesComp.test.js b/test/token/ERC20/extensions/ERC20VotesComp.test.js index 660ed2124..5f95722ad 100644 --- a/test/token/ERC20/extensions/ERC20VotesComp.test.js +++ b/test/token/ERC20/extensions/ERC20VotesComp.test.js @@ -8,11 +8,11 @@ const { fromRpcSig } = require('ethereumjs-util'); const ethSigUtil = require('eth-sig-util'); const Wallet = require('ethereumjs-wallet').default; -const ERC20VotesComp = artifacts.require('$ERC20VotesComp'); - const { batchInBlock } = require('../../../helpers/txpool'); const { getDomain, domainType, domainSeparator } = require('../../../helpers/eip712'); -const { getChainId } = require('../../../helpers/chainid'); +const { clock, clockFromReceipt } = require('../../../helpers/time'); + +const { shouldBehaveLikeEIP6372 } = require('../../../governance/utils/EIP6372.behavior'); const Delegation = [ { name: 'delegatee', type: 'address' }, @@ -20,507 +20,524 @@ const Delegation = [ { name: 'expiry', type: 'uint256' }, ]; +const MODES = { + blocknumber: artifacts.require('$ERC20VotesComp'), + // no timestamp mode for ERC20VotesComp yet +}; + contract('ERC20VotesComp', function (accounts) { const [holder, recipient, holderDelegatee, other1, other2] = accounts; const name = 'My Token'; const symbol = 'MTKN'; - const version = '1'; const supply = new BN('10000000000000000000000000'); - beforeEach(async function () { - this.chainId = await getChainId(); - this.token = await ERC20VotesComp.new(name, symbol, name); - }); - - it('initial nonce is 0', async function () { - expect(await this.token.nonces(holder)).to.be.bignumber.equal('0'); - }); - - it('domain separator', async function () { - expect(await this.token.DOMAIN_SEPARATOR()).to.equal(await getDomain(this.token).then(domainSeparator)); - }); - - it('minting restriction', async function () { - const amount = new BN('2').pow(new BN('96')); - await expectRevert(this.token.$_mint(holder, amount), 'ERC20Votes: total supply risks overflowing votes'); - }); - - describe('set delegation', function () { - describe('call', function () { - it('delegation with balance', async function () { - await this.token.$_mint(holder, supply); - expect(await this.token.delegates(holder)).to.be.equal(ZERO_ADDRESS); - - const { receipt } = await this.token.delegate(holder, { from: holder }); - expectEvent(receipt, 'DelegateChanged', { - delegator: holder, - fromDelegate: ZERO_ADDRESS, - toDelegate: holder, - }); - expectEvent(receipt, 'DelegateVotesChanged', { - delegate: holder, - previousBalance: '0', - newBalance: supply, - }); - - expect(await this.token.delegates(holder)).to.be.equal(holder); - - expect(await this.token.getCurrentVotes(holder)).to.be.bignumber.equal(supply); - expect(await this.token.getPriorVotes(holder, receipt.blockNumber - 1)).to.be.bignumber.equal('0'); - await time.advanceBlock(); - expect(await this.token.getPriorVotes(holder, receipt.blockNumber)).to.be.bignumber.equal(supply); - }); - - it('delegation without balance', async function () { - expect(await this.token.delegates(holder)).to.be.equal(ZERO_ADDRESS); - - const { receipt } = await this.token.delegate(holder, { from: holder }); - expectEvent(receipt, 'DelegateChanged', { - delegator: holder, - fromDelegate: ZERO_ADDRESS, - toDelegate: holder, - }); - expectEvent.notEmitted(receipt, 'DelegateVotesChanged'); - - expect(await this.token.delegates(holder)).to.be.equal(holder); - }); - }); - - describe('with signature', function () { - const delegator = Wallet.generate(); - const delegatorAddress = web3.utils.toChecksumAddress(delegator.getAddressString()); - const nonce = 0; - - const buildData = (contract, message) => - getDomain(contract).then(domain => ({ - primaryType: 'Delegation', - types: { EIP712Domain: domainType(domain), Delegation }, - domain, - message, - })); - + for (const [mode, artifact] of Object.entries(MODES)) { + describe(`vote with ${mode}`, function () { beforeEach(async function () { - await this.token.$_mint(delegatorAddress, supply); + this.token = await artifact.new(name, symbol, name); }); - it('accept signed delegation', async function () { - const { v, r, s } = await buildData(this.token, { - delegatee: delegatorAddress, - nonce, - expiry: MAX_UINT256, - }) - .then(data => ethSigUtil.signTypedMessage(delegator.getPrivateKey(), { data })) - .then(fromRpcSig); + shouldBehaveLikeEIP6372(mode); - expect(await this.token.delegates(delegatorAddress)).to.be.equal(ZERO_ADDRESS); + it('initial nonce is 0', async function () { + expect(await this.token.nonces(holder)).to.be.bignumber.equal('0'); + }); - const { receipt } = await this.token.delegateBySig(delegatorAddress, nonce, MAX_UINT256, v, r, s); - expectEvent(receipt, 'DelegateChanged', { - delegator: delegatorAddress, - fromDelegate: ZERO_ADDRESS, - toDelegate: delegatorAddress, - }); - expectEvent(receipt, 'DelegateVotesChanged', { - delegate: delegatorAddress, - previousBalance: '0', - newBalance: supply, + it('domain separator', async function () { + expect(await this.token.DOMAIN_SEPARATOR()).to.equal(await getDomain(this.token).then(domainSeparator)); + }); + + it('minting restriction', async function () { + const amount = new BN('2').pow(new BN('96')); + await expectRevert(this.token.$_mint(holder, amount), 'ERC20Votes: total supply risks overflowing votes'); + }); + + describe('set delegation', function () { + describe('call', function () { + it('delegation with balance', async function () { + await this.token.$_mint(holder, supply); + expect(await this.token.delegates(holder)).to.be.equal(ZERO_ADDRESS); + + const { receipt } = await this.token.delegate(holder, { from: holder }); + const timepoint = await clockFromReceipt[mode](receipt); + + expectEvent(receipt, 'DelegateChanged', { + delegator: holder, + fromDelegate: ZERO_ADDRESS, + toDelegate: holder, + }); + expectEvent(receipt, 'DelegateVotesChanged', { + delegate: holder, + previousBalance: '0', + newBalance: supply, + }); + + expect(await this.token.delegates(holder)).to.be.equal(holder); + + expect(await this.token.getCurrentVotes(holder)).to.be.bignumber.equal(supply); + expect(await this.token.getPriorVotes(holder, timepoint - 1)).to.be.bignumber.equal('0'); + await time.advanceBlock(); + expect(await this.token.getPriorVotes(holder, timepoint)).to.be.bignumber.equal(supply); + }); + + it('delegation without balance', async function () { + expect(await this.token.delegates(holder)).to.be.equal(ZERO_ADDRESS); + + const { receipt } = await this.token.delegate(holder, { from: holder }); + expectEvent(receipt, 'DelegateChanged', { + delegator: holder, + fromDelegate: ZERO_ADDRESS, + toDelegate: holder, + }); + expectEvent.notEmitted(receipt, 'DelegateVotesChanged'); + + expect(await this.token.delegates(holder)).to.be.equal(holder); + }); }); - expect(await this.token.delegates(delegatorAddress)).to.be.equal(delegatorAddress); + describe('with signature', function () { + const delegator = Wallet.generate(); + const delegatorAddress = web3.utils.toChecksumAddress(delegator.getAddressString()); + const nonce = 0; - expect(await this.token.getCurrentVotes(delegatorAddress)).to.be.bignumber.equal(supply); - expect(await this.token.getPriorVotes(delegatorAddress, receipt.blockNumber - 1)).to.be.bignumber.equal('0'); - await time.advanceBlock(); - expect(await this.token.getPriorVotes(delegatorAddress, receipt.blockNumber)).to.be.bignumber.equal(supply); + const buildData = (contract, message) => + getDomain(contract).then(domain => ({ + primaryType: 'Delegation', + types: { EIP712Domain: domainType(domain), Delegation }, + domain, + message, + })); + + beforeEach(async function () { + await this.token.$_mint(delegatorAddress, supply); + }); + + it('accept signed delegation', async function () { + const { v, r, s } = await buildData(this.token, { + delegatee: delegatorAddress, + nonce, + expiry: MAX_UINT256, + }).then(data => fromRpcSig(ethSigUtil.signTypedMessage(delegator.getPrivateKey(), { data }))); + + expect(await this.token.delegates(delegatorAddress)).to.be.equal(ZERO_ADDRESS); + + const { receipt } = await this.token.delegateBySig(delegatorAddress, nonce, MAX_UINT256, v, r, s); + const timepoint = await clockFromReceipt[mode](receipt); + + expectEvent(receipt, 'DelegateChanged', { + delegator: delegatorAddress, + fromDelegate: ZERO_ADDRESS, + toDelegate: delegatorAddress, + }); + expectEvent(receipt, 'DelegateVotesChanged', { + delegate: delegatorAddress, + previousBalance: '0', + newBalance: supply, + }); + + expect(await this.token.delegates(delegatorAddress)).to.be.equal(delegatorAddress); + + expect(await this.token.getCurrentVotes(delegatorAddress)).to.be.bignumber.equal(supply); + expect(await this.token.getPriorVotes(delegatorAddress, timepoint - 1)).to.be.bignumber.equal('0'); + await time.advanceBlock(); + expect(await this.token.getPriorVotes(delegatorAddress, timepoint)).to.be.bignumber.equal(supply); + }); + + it('rejects reused signature', async function () { + const { v, r, s } = await buildData(this.token, { + delegatee: delegatorAddress, + nonce, + expiry: MAX_UINT256, + }).then(data => fromRpcSig(ethSigUtil.signTypedMessage(delegator.getPrivateKey(), { data }))); + + await this.token.delegateBySig(delegatorAddress, nonce, MAX_UINT256, v, r, s); + + await expectRevert( + this.token.delegateBySig(delegatorAddress, nonce, MAX_UINT256, v, r, s), + 'ERC20Votes: invalid nonce', + ); + }); + + it('rejects bad delegatee', async function () { + const { v, r, s } = await buildData(this.token, { + delegatee: delegatorAddress, + nonce, + expiry: MAX_UINT256, + }).then(data => fromRpcSig(ethSigUtil.signTypedMessage(delegator.getPrivateKey(), { data }))); + + const receipt = await this.token.delegateBySig(holderDelegatee, nonce, MAX_UINT256, v, r, s); + const { args } = receipt.logs.find(({ event }) => event == 'DelegateChanged'); + expect(args.delegator).to.not.be.equal(delegatorAddress); + expect(args.fromDelegate).to.be.equal(ZERO_ADDRESS); + expect(args.toDelegate).to.be.equal(holderDelegatee); + }); + + it('rejects bad nonce', async function () { + const { v, r, s } = await buildData(this.token, { + delegatee: delegatorAddress, + nonce, + expiry: MAX_UINT256, + }).then(data => fromRpcSig(ethSigUtil.signTypedMessage(delegator.getPrivateKey(), { data }))); + + await expectRevert( + this.token.delegateBySig(delegatorAddress, nonce + 1, MAX_UINT256, v, r, s), + 'ERC20Votes: invalid nonce', + ); + }); + + it('rejects expired permit', async function () { + const expiry = (await time.latest()) - time.duration.weeks(1); + const { v, r, s } = await buildData(this.token, { + delegatee: delegatorAddress, + nonce, + expiry, + }).then(data => fromRpcSig(ethSigUtil.signTypedMessage(delegator.getPrivateKey(), { data }))); + + await expectRevert( + this.token.delegateBySig(delegatorAddress, nonce, expiry, v, r, s), + 'ERC20Votes: signature expired', + ); + }); + }); }); - it('rejects reused signature', async function () { - const { v, r, s } = await buildData(this.token, { - delegatee: delegatorAddress, - nonce, - expiry: MAX_UINT256, - }) - .then(data => ethSigUtil.signTypedMessage(delegator.getPrivateKey(), { data })) - .then(fromRpcSig); + describe('change delegation', function () { + beforeEach(async function () { + await this.token.$_mint(holder, supply); + await this.token.delegate(holder, { from: holder }); + }); - await this.token.delegateBySig(delegatorAddress, nonce, MAX_UINT256, v, r, s); + it('call', async function () { + expect(await this.token.delegates(holder)).to.be.equal(holder); - await expectRevert( - this.token.delegateBySig(delegatorAddress, nonce, MAX_UINT256, v, r, s), - 'ERC20Votes: invalid nonce', - ); + const { receipt } = await this.token.delegate(holderDelegatee, { from: holder }); + const timepoint = await clockFromReceipt[mode](receipt); + + expectEvent(receipt, 'DelegateChanged', { + delegator: holder, + fromDelegate: holder, + toDelegate: holderDelegatee, + }); + expectEvent(receipt, 'DelegateVotesChanged', { + delegate: holder, + previousBalance: supply, + newBalance: '0', + }); + expectEvent(receipt, 'DelegateVotesChanged', { + delegate: holderDelegatee, + previousBalance: '0', + newBalance: supply, + }); + + expect(await this.token.delegates(holder)).to.be.equal(holderDelegatee); + + expect(await this.token.getCurrentVotes(holder)).to.be.bignumber.equal('0'); + expect(await this.token.getCurrentVotes(holderDelegatee)).to.be.bignumber.equal(supply); + expect(await this.token.getPriorVotes(holder, timepoint - 1)).to.be.bignumber.equal(supply); + expect(await this.token.getPriorVotes(holderDelegatee, timepoint - 1)).to.be.bignumber.equal('0'); + await time.advanceBlock(); + expect(await this.token.getPriorVotes(holder, timepoint)).to.be.bignumber.equal('0'); + expect(await this.token.getPriorVotes(holderDelegatee, timepoint)).to.be.bignumber.equal(supply); + }); }); - it('rejects bad delegatee', async function () { - const { v, r, s } = await buildData(this.token, { - delegatee: delegatorAddress, - nonce, - expiry: MAX_UINT256, - }) - .then(data => ethSigUtil.signTypedMessage(delegator.getPrivateKey(), { data })) - .then(fromRpcSig); + describe('transfers', function () { + beforeEach(async function () { + await this.token.$_mint(holder, supply); + }); - const receipt = await this.token.delegateBySig(holderDelegatee, nonce, MAX_UINT256, v, r, s); - const { args } = receipt.logs.find(({ event }) => event == 'DelegateChanged'); - expect(args.delegator).to.not.be.equal(delegatorAddress); - expect(args.fromDelegate).to.be.equal(ZERO_ADDRESS); - expect(args.toDelegate).to.be.equal(holderDelegatee); + it('no delegation', async function () { + const { receipt } = await this.token.transfer(recipient, 1, { from: holder }); + expectEvent(receipt, 'Transfer', { from: holder, to: recipient, value: '1' }); + expectEvent.notEmitted(receipt, 'DelegateVotesChanged'); + + this.holderVotes = '0'; + this.recipientVotes = '0'; + }); + + it('sender delegation', async function () { + await this.token.delegate(holder, { from: holder }); + + const { receipt } = await this.token.transfer(recipient, 1, { from: holder }); + expectEvent(receipt, 'Transfer', { from: holder, to: recipient, value: '1' }); + expectEvent(receipt, 'DelegateVotesChanged', { + delegate: holder, + previousBalance: supply, + newBalance: supply.subn(1), + }); + + this.holderVotes = supply.subn(1); + this.recipientVotes = '0'; + }); + + it('receiver delegation', async function () { + await this.token.delegate(recipient, { from: recipient }); + + const { receipt } = await this.token.transfer(recipient, 1, { from: holder }); + expectEvent(receipt, 'Transfer', { from: holder, to: recipient, value: '1' }); + expectEvent(receipt, 'DelegateVotesChanged', { delegate: recipient, previousBalance: '0', newBalance: '1' }); + + this.holderVotes = '0'; + this.recipientVotes = '1'; + }); + + it('full delegation', async function () { + await this.token.delegate(holder, { from: holder }); + await this.token.delegate(recipient, { from: recipient }); + + const { receipt } = await this.token.transfer(recipient, 1, { from: holder }); + expectEvent(receipt, 'Transfer', { from: holder, to: recipient, value: '1' }); + expectEvent(receipt, 'DelegateVotesChanged', { + delegate: holder, + previousBalance: supply, + newBalance: supply.subn(1), + }); + expectEvent(receipt, 'DelegateVotesChanged', { delegate: recipient, previousBalance: '0', newBalance: '1' }); + + this.holderVotes = supply.subn(1); + this.recipientVotes = '1'; + }); + + afterEach(async function () { + expect(await this.token.getCurrentVotes(holder)).to.be.bignumber.equal(this.holderVotes); + expect(await this.token.getCurrentVotes(recipient)).to.be.bignumber.equal(this.recipientVotes); + + // need to advance 2 blocks to see the effect of a transfer on "getPriorVotes" + const timepoint = await clock[mode](); + await time.advanceBlock(); + expect(await this.token.getPriorVotes(holder, timepoint)).to.be.bignumber.equal(this.holderVotes); + expect(await this.token.getPriorVotes(recipient, timepoint)).to.be.bignumber.equal(this.recipientVotes); + }); }); - it('rejects bad nonce', async function () { - const { v, r, s } = await buildData(this.token, { - delegatee: delegatorAddress, - nonce, - expiry: MAX_UINT256, - }) - .then(data => ethSigUtil.signTypedMessage(delegator.getPrivateKey(), { data })) - .then(fromRpcSig); + // The following tests are a adaptation of https://github.com/compound-finance/compound-protocol/blob/master/tests/Governance/CompTest.js. + describe('Compound test suite', function () { + beforeEach(async function () { + await this.token.$_mint(holder, supply); + }); - await expectRevert( - this.token.delegateBySig(delegatorAddress, nonce + 1, MAX_UINT256, v, r, s), - 'ERC20Votes: invalid nonce', - ); + describe('balanceOf', function () { + it('grants to initial account', async function () { + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal('10000000000000000000000000'); + }); + }); + + describe('numCheckpoints', function () { + it('returns the number of checkpoints for a delegate', async function () { + await this.token.transfer(recipient, '100', { from: holder }); //give an account a few tokens for readability + expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('0'); + + const t1 = await this.token.delegate(other1, { from: recipient }); + t1.timepoint = await clockFromReceipt[mode](t1.receipt); + expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('1'); + + const t2 = await this.token.transfer(other2, 10, { from: recipient }); + t2.timepoint = await clockFromReceipt[mode](t2.receipt); + expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('2'); + + const t3 = await this.token.transfer(other2, 10, { from: recipient }); + t3.timepoint = await clockFromReceipt[mode](t3.receipt); + expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('3'); + + const t4 = await this.token.transfer(recipient, 20, { from: holder }); + t4.timepoint = await clockFromReceipt[mode](t4.receipt); + expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('4'); + + expect(await this.token.checkpoints(other1, 0)).to.be.deep.equal([t1.timepoint.toString(), '100']); + expect(await this.token.checkpoints(other1, 1)).to.be.deep.equal([t2.timepoint.toString(), '90']); + expect(await this.token.checkpoints(other1, 2)).to.be.deep.equal([t3.timepoint.toString(), '80']); + expect(await this.token.checkpoints(other1, 3)).to.be.deep.equal([t4.timepoint.toString(), '100']); + + await time.advanceBlock(); + expect(await this.token.getPriorVotes(other1, t1.timepoint)).to.be.bignumber.equal('100'); + expect(await this.token.getPriorVotes(other1, t2.timepoint)).to.be.bignumber.equal('90'); + expect(await this.token.getPriorVotes(other1, t3.timepoint)).to.be.bignumber.equal('80'); + expect(await this.token.getPriorVotes(other1, t4.timepoint)).to.be.bignumber.equal('100'); + }); + + it('does not add more than one checkpoint in a block', async function () { + await this.token.transfer(recipient, '100', { from: holder }); + expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('0'); + + const [t1, t2, t3] = await batchInBlock([ + () => this.token.delegate(other1, { from: recipient, gas: 100000 }), + () => this.token.transfer(other2, 10, { from: recipient, gas: 100000 }), + () => this.token.transfer(other2, 10, { from: recipient, gas: 100000 }), + ]); + t1.timepoint = await clockFromReceipt[mode](t1.receipt); + t2.timepoint = await clockFromReceipt[mode](t2.receipt); + t3.timepoint = await clockFromReceipt[mode](t3.receipt); + + expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('1'); + expect(await this.token.checkpoints(other1, 0)).to.be.deep.equal([t1.timepoint.toString(), '80']); + + const t4 = await this.token.transfer(recipient, 20, { from: holder }); + t4.timepoint = await clockFromReceipt[mode](t4.receipt); + + expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('2'); + expect(await this.token.checkpoints(other1, 1)).to.be.deep.equal([t4.timepoint.toString(), '100']); + }); + }); + + describe('getPriorVotes', function () { + it('reverts if block number >= current block', async function () { + await expectRevert(this.token.getPriorVotes(other1, 5e10), 'ERC20Votes: future lookup'); + }); + + it('returns 0 if there are no checkpoints', async function () { + expect(await this.token.getPriorVotes(other1, 0)).to.be.bignumber.equal('0'); + }); + + it('returns the latest block if >= last checkpoint block', async function () { + const { receipt } = await this.token.delegate(other1, { from: holder }); + const timepoint = await clockFromReceipt[mode](receipt); + await time.advanceBlock(); + await time.advanceBlock(); + + expect(await this.token.getPriorVotes(other1, timepoint)).to.be.bignumber.equal( + '10000000000000000000000000', + ); + expect(await this.token.getPriorVotes(other1, timepoint + 1)).to.be.bignumber.equal( + '10000000000000000000000000', + ); + }); + + it('returns zero if < first checkpoint block', async function () { + await time.advanceBlock(); + const { receipt } = await this.token.delegate(other1, { from: holder }); + const timepoint = await clockFromReceipt[mode](receipt); + await time.advanceBlock(); + await time.advanceBlock(); + + expect(await this.token.getPriorVotes(other1, timepoint - 1)).to.be.bignumber.equal('0'); + expect(await this.token.getPriorVotes(other1, timepoint + 1)).to.be.bignumber.equal( + '10000000000000000000000000', + ); + }); + + it('generally returns the voting balance at the appropriate checkpoint', async function () { + const t1 = await this.token.delegate(other1, { from: holder }); + await time.advanceBlock(); + await time.advanceBlock(); + const t2 = await this.token.transfer(other2, 10, { from: holder }); + await time.advanceBlock(); + await time.advanceBlock(); + const t3 = await this.token.transfer(other2, 10, { from: holder }); + await time.advanceBlock(); + await time.advanceBlock(); + const t4 = await this.token.transfer(holder, 20, { from: other2 }); + await time.advanceBlock(); + await time.advanceBlock(); + + t1.timepoint = await clockFromReceipt[mode](t1.receipt); + t2.timepoint = await clockFromReceipt[mode](t2.receipt); + t3.timepoint = await clockFromReceipt[mode](t3.receipt); + t4.timepoint = await clockFromReceipt[mode](t4.receipt); + + expect(await this.token.getPriorVotes(other1, t1.timepoint - 1)).to.be.bignumber.equal('0'); + expect(await this.token.getPriorVotes(other1, t1.timepoint)).to.be.bignumber.equal( + '10000000000000000000000000', + ); + expect(await this.token.getPriorVotes(other1, t1.timepoint + 1)).to.be.bignumber.equal( + '10000000000000000000000000', + ); + expect(await this.token.getPriorVotes(other1, t2.timepoint)).to.be.bignumber.equal( + '9999999999999999999999990', + ); + expect(await this.token.getPriorVotes(other1, t2.timepoint + 1)).to.be.bignumber.equal( + '9999999999999999999999990', + ); + expect(await this.token.getPriorVotes(other1, t3.timepoint)).to.be.bignumber.equal( + '9999999999999999999999980', + ); + expect(await this.token.getPriorVotes(other1, t3.timepoint + 1)).to.be.bignumber.equal( + '9999999999999999999999980', + ); + expect(await this.token.getPriorVotes(other1, t4.timepoint)).to.be.bignumber.equal( + '10000000000000000000000000', + ); + expect(await this.token.getPriorVotes(other1, t4.timepoint + 1)).to.be.bignumber.equal( + '10000000000000000000000000', + ); + }); + }); }); - it('rejects expired permit', async function () { - const expiry = (await time.latest()) - time.duration.weeks(1); + describe('getPastTotalSupply', function () { + beforeEach(async function () { + await this.token.delegate(holder, { from: holder }); + }); - const { v, r, s } = await buildData(this.token, { - delegatee: delegatorAddress, - nonce, - expiry, - }) - .then(data => ethSigUtil.signTypedMessage(delegator.getPrivateKey(), { data })) - .then(fromRpcSig); + it('reverts if block number >= current block', async function () { + await expectRevert(this.token.getPastTotalSupply(5e10), 'ERC20Votes: future lookup'); + }); - await expectRevert( - this.token.delegateBySig(delegatorAddress, nonce, expiry, v, r, s), - 'ERC20Votes: signature expired', - ); + it('returns 0 if there are no checkpoints', async function () { + expect(await this.token.getPastTotalSupply(0)).to.be.bignumber.equal('0'); + }); + + it('returns the latest block if >= last checkpoint block', async function () { + const { receipt } = await this.token.$_mint(holder, supply); + const timepoint = await clockFromReceipt[mode](receipt); + await time.advanceBlock(); + await time.advanceBlock(); + + expect(await this.token.getPastTotalSupply(timepoint)).to.be.bignumber.equal(supply); + expect(await this.token.getPastTotalSupply(timepoint + 1)).to.be.bignumber.equal(supply); + }); + + it('returns zero if < first checkpoint block', async function () { + await time.advanceBlock(); + const { receipt } = await this.token.$_mint(holder, supply); + const timepoint = await clockFromReceipt[mode](receipt); + await time.advanceBlock(); + await time.advanceBlock(); + + expect(await this.token.getPastTotalSupply(timepoint - 1)).to.be.bignumber.equal('0'); + expect(await this.token.getPastTotalSupply(timepoint + 1)).to.be.bignumber.equal( + '10000000000000000000000000', + ); + }); + + it('generally returns the voting balance at the appropriate checkpoint', async function () { + const t1 = await this.token.$_mint(holder, supply); + await time.advanceBlock(); + await time.advanceBlock(); + const t2 = await this.token.$_burn(holder, 10); + await time.advanceBlock(); + await time.advanceBlock(); + const t3 = await this.token.$_burn(holder, 10); + await time.advanceBlock(); + await time.advanceBlock(); + const t4 = await this.token.$_mint(holder, 20); + await time.advanceBlock(); + await time.advanceBlock(); + + t1.timepoint = await clockFromReceipt[mode](t1.receipt); + t2.timepoint = await clockFromReceipt[mode](t2.receipt); + t3.timepoint = await clockFromReceipt[mode](t3.receipt); + t4.timepoint = await clockFromReceipt[mode](t4.receipt); + + expect(await this.token.getPastTotalSupply(t1.timepoint - 1)).to.be.bignumber.equal('0'); + expect(await this.token.getPastTotalSupply(t1.timepoint)).to.be.bignumber.equal('10000000000000000000000000'); + expect(await this.token.getPastTotalSupply(t1.timepoint + 1)).to.be.bignumber.equal( + '10000000000000000000000000', + ); + expect(await this.token.getPastTotalSupply(t2.timepoint)).to.be.bignumber.equal('9999999999999999999999990'); + expect(await this.token.getPastTotalSupply(t2.timepoint + 1)).to.be.bignumber.equal( + '9999999999999999999999990', + ); + expect(await this.token.getPastTotalSupply(t3.timepoint)).to.be.bignumber.equal('9999999999999999999999980'); + expect(await this.token.getPastTotalSupply(t3.timepoint + 1)).to.be.bignumber.equal( + '9999999999999999999999980', + ); + expect(await this.token.getPastTotalSupply(t4.timepoint)).to.be.bignumber.equal('10000000000000000000000000'); + expect(await this.token.getPastTotalSupply(t4.timepoint + 1)).to.be.bignumber.equal( + '10000000000000000000000000', + ); + }); }); }); - }); - - describe('change delegation', function () { - beforeEach(async function () { - await this.token.$_mint(holder, supply); - await this.token.delegate(holder, { from: holder }); - }); - - it('call', async function () { - expect(await this.token.delegates(holder)).to.be.equal(holder); - - const { receipt } = await this.token.delegate(holderDelegatee, { from: holder }); - expectEvent(receipt, 'DelegateChanged', { - delegator: holder, - fromDelegate: holder, - toDelegate: holderDelegatee, - }); - expectEvent(receipt, 'DelegateVotesChanged', { - delegate: holder, - previousBalance: supply, - newBalance: '0', - }); - expectEvent(receipt, 'DelegateVotesChanged', { - delegate: holderDelegatee, - previousBalance: '0', - newBalance: supply, - }); - - expect(await this.token.delegates(holder)).to.be.equal(holderDelegatee); - - expect(await this.token.getCurrentVotes(holder)).to.be.bignumber.equal('0'); - expect(await this.token.getCurrentVotes(holderDelegatee)).to.be.bignumber.equal(supply); - expect(await this.token.getPriorVotes(holder, receipt.blockNumber - 1)).to.be.bignumber.equal(supply); - expect(await this.token.getPriorVotes(holderDelegatee, receipt.blockNumber - 1)).to.be.bignumber.equal('0'); - await time.advanceBlock(); - expect(await this.token.getPriorVotes(holder, receipt.blockNumber)).to.be.bignumber.equal('0'); - expect(await this.token.getPriorVotes(holderDelegatee, receipt.blockNumber)).to.be.bignumber.equal(supply); - }); - }); - - describe('transfers', function () { - beforeEach(async function () { - await this.token.$_mint(holder, supply); - }); - - it('no delegation', async function () { - const { receipt } = await this.token.transfer(recipient, 1, { from: holder }); - expectEvent(receipt, 'Transfer', { from: holder, to: recipient, value: '1' }); - expectEvent.notEmitted(receipt, 'DelegateVotesChanged'); - - this.holderVotes = '0'; - this.recipientVotes = '0'; - }); - - it('sender delegation', async function () { - await this.token.delegate(holder, { from: holder }); - - const { receipt } = await this.token.transfer(recipient, 1, { from: holder }); - expectEvent(receipt, 'Transfer', { from: holder, to: recipient, value: '1' }); - expectEvent(receipt, 'DelegateVotesChanged', { - delegate: holder, - previousBalance: supply, - newBalance: supply.subn(1), - }); - - this.holderVotes = supply.subn(1); - this.recipientVotes = '0'; - }); - - it('receiver delegation', async function () { - await this.token.delegate(recipient, { from: recipient }); - - const { receipt } = await this.token.transfer(recipient, 1, { from: holder }); - expectEvent(receipt, 'Transfer', { from: holder, to: recipient, value: '1' }); - expectEvent(receipt, 'DelegateVotesChanged', { delegate: recipient, previousBalance: '0', newBalance: '1' }); - - this.holderVotes = '0'; - this.recipientVotes = '1'; - }); - - it('full delegation', async function () { - await this.token.delegate(holder, { from: holder }); - await this.token.delegate(recipient, { from: recipient }); - - const { receipt } = await this.token.transfer(recipient, 1, { from: holder }); - expectEvent(receipt, 'Transfer', { from: holder, to: recipient, value: '1' }); - expectEvent(receipt, 'DelegateVotesChanged', { - delegate: holder, - previousBalance: supply, - newBalance: supply.subn(1), - }); - expectEvent(receipt, 'DelegateVotesChanged', { delegate: recipient, previousBalance: '0', newBalance: '1' }); - - this.holderVotes = supply.subn(1); - this.recipientVotes = '1'; - }); - - afterEach(async function () { - expect(await this.token.getCurrentVotes(holder)).to.be.bignumber.equal(this.holderVotes); - expect(await this.token.getCurrentVotes(recipient)).to.be.bignumber.equal(this.recipientVotes); - - // need to advance 2 blocks to see the effect of a transfer on "getPriorVotes" - const blockNumber = await time.latestBlock(); - await time.advanceBlock(); - expect(await this.token.getPriorVotes(holder, blockNumber)).to.be.bignumber.equal(this.holderVotes); - expect(await this.token.getPriorVotes(recipient, blockNumber)).to.be.bignumber.equal(this.recipientVotes); - }); - }); - - // The following tests are a adaptation of https://github.com/compound-finance/compound-protocol/blob/master/tests/Governance/CompTest.js. - describe('Compound test suite', function () { - beforeEach(async function () { - await this.token.$_mint(holder, supply); - }); - - describe('balanceOf', function () { - it('grants to initial account', async function () { - expect(await this.token.balanceOf(holder)).to.be.bignumber.equal('10000000000000000000000000'); - }); - }); - - describe('numCheckpoints', function () { - it('returns the number of checkpoints for a delegate', async function () { - await this.token.transfer(recipient, '100', { from: holder }); //give an account a few tokens for readability - expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('0'); - - const t1 = await this.token.delegate(other1, { from: recipient }); - expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('1'); - - const t2 = await this.token.transfer(other2, 10, { from: recipient }); - expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('2'); - - const t3 = await this.token.transfer(other2, 10, { from: recipient }); - expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('3'); - - const t4 = await this.token.transfer(recipient, 20, { from: holder }); - expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('4'); - - expect(await this.token.checkpoints(other1, 0)).to.be.deep.equal([t1.receipt.blockNumber.toString(), '100']); - expect(await this.token.checkpoints(other1, 1)).to.be.deep.equal([t2.receipt.blockNumber.toString(), '90']); - expect(await this.token.checkpoints(other1, 2)).to.be.deep.equal([t3.receipt.blockNumber.toString(), '80']); - expect(await this.token.checkpoints(other1, 3)).to.be.deep.equal([t4.receipt.blockNumber.toString(), '100']); - - await time.advanceBlock(); - expect(await this.token.getPriorVotes(other1, t1.receipt.blockNumber)).to.be.bignumber.equal('100'); - expect(await this.token.getPriorVotes(other1, t2.receipt.blockNumber)).to.be.bignumber.equal('90'); - expect(await this.token.getPriorVotes(other1, t3.receipt.blockNumber)).to.be.bignumber.equal('80'); - expect(await this.token.getPriorVotes(other1, t4.receipt.blockNumber)).to.be.bignumber.equal('100'); - }); - - it('does not add more than one checkpoint in a block', async function () { - await this.token.transfer(recipient, '100', { from: holder }); - expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('0'); - - const [t1, t2, t3] = await batchInBlock([ - () => this.token.delegate(other1, { from: recipient, gas: 100000 }), - () => this.token.transfer(other2, 10, { from: recipient, gas: 100000 }), - () => this.token.transfer(other2, 10, { from: recipient, gas: 100000 }), - ]); - expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('1'); - expect(await this.token.checkpoints(other1, 0)).to.be.deep.equal([t1.receipt.blockNumber.toString(), '80']); - // expectReve(await this.token.checkpoints(other1, 1)).to.be.deep.equal([ '0', '0' ]); // Reverts due to array overflow check - // expect(await this.token.checkpoints(other1, 2)).to.be.deep.equal([ '0', '0' ]); // Reverts due to array overflow check - - const t4 = await this.token.transfer(recipient, 20, { from: holder }); - expect(await this.token.numCheckpoints(other1)).to.be.bignumber.equal('2'); - expect(await this.token.checkpoints(other1, 1)).to.be.deep.equal([t4.receipt.blockNumber.toString(), '100']); - }); - }); - - describe('getPriorVotes', function () { - it('reverts if block number >= current block', async function () { - await expectRevert(this.token.getPriorVotes(other1, 5e10), 'ERC20Votes: block not yet mined'); - }); - - it('returns 0 if there are no checkpoints', async function () { - expect(await this.token.getPriorVotes(other1, 0)).to.be.bignumber.equal('0'); - }); - - it('returns the latest block if >= last checkpoint block', async function () { - const t1 = await this.token.delegate(other1, { from: holder }); - await time.advanceBlock(); - await time.advanceBlock(); - - expect(await this.token.getPriorVotes(other1, t1.receipt.blockNumber)).to.be.bignumber.equal( - '10000000000000000000000000', - ); - expect(await this.token.getPriorVotes(other1, t1.receipt.blockNumber + 1)).to.be.bignumber.equal( - '10000000000000000000000000', - ); - }); - - it('returns zero if < first checkpoint block', async function () { - await time.advanceBlock(); - const t1 = await this.token.delegate(other1, { from: holder }); - await time.advanceBlock(); - await time.advanceBlock(); - - expect(await this.token.getPriorVotes(other1, t1.receipt.blockNumber - 1)).to.be.bignumber.equal('0'); - expect(await this.token.getPriorVotes(other1, t1.receipt.blockNumber + 1)).to.be.bignumber.equal( - '10000000000000000000000000', - ); - }); - - it('generally returns the voting balance at the appropriate checkpoint', async function () { - const t1 = await this.token.delegate(other1, { from: holder }); - await time.advanceBlock(); - await time.advanceBlock(); - const t2 = await this.token.transfer(other2, 10, { from: holder }); - await time.advanceBlock(); - await time.advanceBlock(); - const t3 = await this.token.transfer(other2, 10, { from: holder }); - await time.advanceBlock(); - await time.advanceBlock(); - const t4 = await this.token.transfer(holder, 20, { from: other2 }); - await time.advanceBlock(); - await time.advanceBlock(); - - expect(await this.token.getPriorVotes(other1, t1.receipt.blockNumber - 1)).to.be.bignumber.equal('0'); - expect(await this.token.getPriorVotes(other1, t1.receipt.blockNumber)).to.be.bignumber.equal( - '10000000000000000000000000', - ); - expect(await this.token.getPriorVotes(other1, t1.receipt.blockNumber + 1)).to.be.bignumber.equal( - '10000000000000000000000000', - ); - expect(await this.token.getPriorVotes(other1, t2.receipt.blockNumber)).to.be.bignumber.equal( - '9999999999999999999999990', - ); - expect(await this.token.getPriorVotes(other1, t2.receipt.blockNumber + 1)).to.be.bignumber.equal( - '9999999999999999999999990', - ); - expect(await this.token.getPriorVotes(other1, t3.receipt.blockNumber)).to.be.bignumber.equal( - '9999999999999999999999980', - ); - expect(await this.token.getPriorVotes(other1, t3.receipt.blockNumber + 1)).to.be.bignumber.equal( - '9999999999999999999999980', - ); - expect(await this.token.getPriorVotes(other1, t4.receipt.blockNumber)).to.be.bignumber.equal( - '10000000000000000000000000', - ); - expect(await this.token.getPriorVotes(other1, t4.receipt.blockNumber + 1)).to.be.bignumber.equal( - '10000000000000000000000000', - ); - }); - }); - }); - - describe('getPastTotalSupply', function () { - beforeEach(async function () { - await this.token.delegate(holder, { from: holder }); - }); - - it('reverts if block number >= current block', async function () { - await expectRevert(this.token.getPastTotalSupply(5e10), 'ERC20Votes: block not yet mined'); - }); - - it('returns 0 if there are no checkpoints', async function () { - expect(await this.token.getPastTotalSupply(0)).to.be.bignumber.equal('0'); - }); - - it('returns the latest block if >= last checkpoint block', async function () { - t1 = await this.token.$_mint(holder, supply); - - await time.advanceBlock(); - await time.advanceBlock(); - - expect(await this.token.getPastTotalSupply(t1.receipt.blockNumber)).to.be.bignumber.equal(supply); - expect(await this.token.getPastTotalSupply(t1.receipt.blockNumber + 1)).to.be.bignumber.equal(supply); - }); - - it('returns zero if < first checkpoint block', async function () { - await time.advanceBlock(); - const t1 = await this.token.$_mint(holder, supply); - await time.advanceBlock(); - await time.advanceBlock(); - - expect(await this.token.getPastTotalSupply(t1.receipt.blockNumber - 1)).to.be.bignumber.equal('0'); - expect(await this.token.getPastTotalSupply(t1.receipt.blockNumber + 1)).to.be.bignumber.equal( - '10000000000000000000000000', - ); - }); - - it('generally returns the voting balance at the appropriate checkpoint', async function () { - const t1 = await this.token.$_mint(holder, supply); - await time.advanceBlock(); - await time.advanceBlock(); - const t2 = await this.token.$_burn(holder, 10); - await time.advanceBlock(); - await time.advanceBlock(); - const t3 = await this.token.$_burn(holder, 10); - await time.advanceBlock(); - await time.advanceBlock(); - const t4 = await this.token.$_mint(holder, 20); - await time.advanceBlock(); - await time.advanceBlock(); - - expect(await this.token.getPastTotalSupply(t1.receipt.blockNumber - 1)).to.be.bignumber.equal('0'); - expect(await this.token.getPastTotalSupply(t1.receipt.blockNumber)).to.be.bignumber.equal( - '10000000000000000000000000', - ); - expect(await this.token.getPastTotalSupply(t1.receipt.blockNumber + 1)).to.be.bignumber.equal( - '10000000000000000000000000', - ); - expect(await this.token.getPastTotalSupply(t2.receipt.blockNumber)).to.be.bignumber.equal( - '9999999999999999999999990', - ); - expect(await this.token.getPastTotalSupply(t2.receipt.blockNumber + 1)).to.be.bignumber.equal( - '9999999999999999999999990', - ); - expect(await this.token.getPastTotalSupply(t3.receipt.blockNumber)).to.be.bignumber.equal( - '9999999999999999999999980', - ); - expect(await this.token.getPastTotalSupply(t3.receipt.blockNumber + 1)).to.be.bignumber.equal( - '9999999999999999999999980', - ); - expect(await this.token.getPastTotalSupply(t4.receipt.blockNumber)).to.be.bignumber.equal( - '10000000000000000000000000', - ); - expect(await this.token.getPastTotalSupply(t4.receipt.blockNumber + 1)).to.be.bignumber.equal( - '10000000000000000000000000', - ); - }); - }); + } }); diff --git a/test/token/ERC721/extensions/ERC721Votes.test.js b/test/token/ERC721/extensions/ERC721Votes.test.js index f7baef4c1..92032db87 100644 --- a/test/token/ERC721/extensions/ERC721Votes.test.js +++ b/test/token/ERC721/extensions/ERC721Votes.test.js @@ -178,6 +178,7 @@ contract('ERC721Votes', function (accounts) { this.name = 'My Vote'; }); + // includes EIP6372 behavior check shouldBehaveLikeVotes(); }); }); diff --git a/test/utils/Checkpoints.test.js b/test/utils/Checkpoints.test.js index d43d469cc..48a00e31a 100644 --- a/test/utils/Checkpoints.test.js +++ b/test/utils/Checkpoints.test.js @@ -117,8 +117,10 @@ contract('Checkpoints', function () { const latestCheckpoint = (self, ...args) => self.methods[`$latestCheckpoint_Checkpoints_Trace${length}(uint256)`](0, ...args); const push = (self, ...args) => self.methods[`$push(uint256,uint${256 - length},uint${length})`](0, ...args); - const upperLookup = (self, ...args) => self.methods[`$upperLookup(uint256,uint${256 - length})`](0, ...args); const lowerLookup = (self, ...args) => self.methods[`$lowerLookup(uint256,uint${256 - length})`](0, ...args); + const upperLookup = (self, ...args) => self.methods[`$upperLookup(uint256,uint${256 - length})`](0, ...args); + const upperLookupRecent = (self, ...args) => + self.methods[`$upperLookupRecent(uint256,uint${256 - length})`](0, ...args); const getLength = (self, ...args) => self.methods[`$length_Checkpoints_Trace${length}(uint256)`](0, ...args); describe('without checkpoints', function () { @@ -134,6 +136,7 @@ contract('Checkpoints', function () { it('lookup returns 0', async function () { expect(await lowerLookup(this.mock, 0)).to.be.bignumber.equal('0'); expect(await upperLookup(this.mock, 0)).to.be.bignumber.equal('0'); + expect(await upperLookupRecent(this.mock, 0)).to.be.bignumber.equal('0'); }); }); @@ -190,11 +193,33 @@ contract('Checkpoints', function () { } }); - it('upper lookup', async function () { + it('upper lookup & upperLookupRecent', async function () { for (let i = 0; i < 14; ++i) { const value = last(this.checkpoints.filter(x => i >= x.key))?.value || '0'; expect(await upperLookup(this.mock, i)).to.be.bignumber.equal(value); + expect(await upperLookupRecent(this.mock, i)).to.be.bignumber.equal(value); + } + }); + + it('upperLookupRecent with more than 5 checkpoints', async function () { + const moreCheckpoints = [ + { key: '12', value: '22' }, + { key: '13', value: '131' }, + { key: '17', value: '45' }, + { key: '19', value: '31452' }, + { key: '21', value: '0' }, + ]; + const allCheckpoints = [].concat(this.checkpoints, moreCheckpoints); + + for (const { key, value } of moreCheckpoints) { + await push(this.mock, key, value); + } + + for (let i = 0; i < 25; ++i) { + const value = last(allCheckpoints.filter(x => i >= x.key))?.value || '0'; + expect(await upperLookup(this.mock, i)).to.be.bignumber.equal(value); + expect(await upperLookupRecent(this.mock, i)).to.be.bignumber.equal(value); } }); }); From 6259e13a0c92547646f1dd1764583e86bb997441 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Garc=C3=ADa?= Date: Thu, 9 Feb 2023 15:36:14 -0600 Subject: [PATCH 029/133] Improve ERC721 Wrapper tests (#4039) --- test/token/ERC721/extensions/ERC721Wrapper.test.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/token/ERC721/extensions/ERC721Wrapper.test.js b/test/token/ERC721/extensions/ERC721Wrapper.test.js index 5c83d73cc..def6ca7ee 100644 --- a/test/token/ERC721/extensions/ERC721Wrapper.test.js +++ b/test/token/ERC721/extensions/ERC721Wrapper.test.js @@ -196,11 +196,21 @@ contract('ERC721Wrapper', function (accounts) { to: initialHolder, tokenId: firstTokenId, }); + await expectEvent.inTransaction(tx, this.underlying, 'Transfer', { + from: this.token.address, + to: initialHolder, + tokenId: secondTokenId, + }); await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: initialHolder, to: constants.ZERO_ADDRESS, tokenId: firstTokenId, }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: initialHolder, + to: constants.ZERO_ADDRESS, + tokenId: secondTokenId, + }); }); it('works to another account', async function () { From dfcc1d16c5efd0fd2a7abac56680810c861a9cd3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Feb 2023 18:42:08 -0300 Subject: [PATCH 030/133] Bump http-cache-semantics from 4.1.0 to 4.1.1 (#4024) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index a663055fd..4f808cf30 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8426,9 +8426,9 @@ } }, "node_modules/http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", "dev": true }, "node_modules/http-errors": { @@ -22946,9 +22946,9 @@ } }, "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", "dev": true }, "http-errors": { From 5a00628ed3d6ce3154cee4d2cc93fad920e8ea30 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 10 Feb 2023 15:21:45 -0300 Subject: [PATCH 031/133] Update getsentry/action-github-app-token action to v2 (#4036) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/upgradeable.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/upgradeable.yml b/.github/workflows/upgradeable.yml index a94f78c98..a7ed8da88 100644 --- a/.github/workflows/upgradeable.yml +++ b/.github/workflows/upgradeable.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - id: app - uses: getsentry/action-github-app-token@v1 + uses: getsentry/action-github-app-token@v2 with: app_id: ${{ secrets.UPGRADEABLE_APP_ID }} private_key: ${{ secrets.UPGRADEABLE_APP_PK }} From 2c711d0b0513d283b27a3b28df06d558a19c3aaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Garc=C3=ADa?= Date: Tue, 14 Feb 2023 14:47:07 -0600 Subject: [PATCH 032/133] Restrict ERC721Wrapper wrap by direct transfer (#4043) Co-authored-by: Hadrien Croubois --- .../token/ERC721/extensions/ERC721Wrapper.sol | 17 +++----- .../ERC721/extensions/ERC721Wrapper.test.js | 39 ++----------------- 2 files changed, 9 insertions(+), 47 deletions(-) diff --git a/contracts/token/ERC721/extensions/ERC721Wrapper.sol b/contracts/token/ERC721/extensions/ERC721Wrapper.sol index 87729188a..f10d55564 100644 --- a/contracts/token/ERC721/extensions/ERC721Wrapper.sol +++ b/contracts/token/ERC721/extensions/ERC721Wrapper.sol @@ -17,10 +17,6 @@ import "../utils/ERC721Holder.sol"; abstract contract ERC721Wrapper is ERC721, ERC721Holder { IERC721 private immutable _underlying; - // Kept as bytes12 so it can be packed with an address - // Equal to 0xb125e89df18e2ceac5fd2fa8 - bytes12 public constant WRAPPER_ACCEPT_MAGIC = bytes12(keccak256("WRAPPER_ACCEPT_MAGIC")); - constructor(IERC721 underlyingToken) { _underlying = underlyingToken; } @@ -29,7 +25,7 @@ abstract contract ERC721Wrapper is ERC721, ERC721Holder { * @dev Allow a user to deposit underlying tokens and mint the corresponding tokenIds. */ function depositFor(address account, uint256[] memory tokenIds) public virtual returns (bool) { - bytes memory data = abi.encodePacked(WRAPPER_ACCEPT_MAGIC, account); + bytes memory data = abi.encodePacked(account); uint256 length = tokenIds.length; for (uint256 i = 0; i < length; ++i) { @@ -61,23 +57,22 @@ abstract contract ERC721Wrapper is ERC721, ERC721Holder { * @dev Overrides {IERC721Receiver-onERC721Received} to allow minting on direct ERC721 transfers to * this contract. * - * In case there's data attached, it validates that the sender is aware of this contract's existence and behavior - * by checking a magic value (`WRAPPER_ACCEPT_MAGIC`) in the first 12 bytes. If it also matches, the rest 20 - * bytes are used as an address to send the tokens to. + * In case there's data attached, it validates that the operator is this contract, so only trusted data + * is accepted from {depositFor}. * * WARNING: Doesn't work with unsafe transfers (eg. {IERC721-transferFrom}). Use {ERC721Wrapper-_recover} * for recovering in that scenario. */ function onERC721Received( - address, + address operator, address from, uint256 tokenId, bytes memory data ) public override returns (bytes4) { require(address(underlying()) == _msgSender(), "ERC721Wrapper: caller is not underlying"); if (data.length > 0) { - require(data.length == 32 && WRAPPER_ACCEPT_MAGIC == bytes12(data), "ERC721Wrapper: Invalid data format"); - from = address(bytes20(bytes32(data) << 96)); + require(data.length == 20 && operator == address(this), "ERC721Wrapper: Invalid data format"); + from = address(bytes20(data)); } _safeMint(from, tokenId); return IERC721Receiver.onERC721Received.selector; diff --git a/test/token/ERC721/extensions/ERC721Wrapper.test.js b/test/token/ERC721/extensions/ERC721Wrapper.test.js index def6ca7ee..0558dfa37 100644 --- a/test/token/ERC721/extensions/ERC721Wrapper.test.js +++ b/test/token/ERC721/extensions/ERC721Wrapper.test.js @@ -1,6 +1,5 @@ const { BN, expectEvent, constants, expectRevert } = require('@openzeppelin/test-helpers'); const { expect } = require('chai'); -const { keccakFromString, bufferToHex } = require('ethereumjs-util'); const { shouldBehaveLikeERC721 } = require('../ERC721.behavior'); @@ -230,27 +229,13 @@ contract('ERC721Wrapper', function (accounts) { }); describe('onERC721Received', function () { - const WRAPPER_ACCEPT_MAGIC = bufferToHex(keccakFromString('WRAPPER_ACCEPT_MAGIC')).slice(0, 26); // Include 0x - - const magicWithAddresss = address => - web3.utils.encodePacked( - { - value: WRAPPER_ACCEPT_MAGIC, - type: 'bytes12', - }, - { - value: address, - type: 'address', - }, - ); - it('only allows calls from underlying', async function () { await expectRevert( this.token.onERC721Received( initialHolder, this.token.address, firstTokenId, - magicWithAddresss(anotherAccount), // Correct data + anotherAccount, // Correct data { from: anotherAccount }, ), 'ERC721Wrapper: caller is not underlying', @@ -273,13 +258,13 @@ contract('ERC721Wrapper', function (accounts) { ); }); - it('reverts with the magic value and data length different to 32', async function () { + it('reverts with correct data from an untrusted operator', async function () { await expectRevert( this.underlying.methods['safeTransferFrom(address,address,uint256,bytes)']( initialHolder, this.token.address, firstTokenId, - WRAPPER_ACCEPT_MAGIC, // Reverts for any non-32 bytes value + anotherAccount, { from: initialHolder, }, @@ -287,24 +272,6 @@ contract('ERC721Wrapper', function (accounts) { 'ERC721Wrapper: Invalid data format', ); }); - - it('mints token to specific holder with address after magic value', async function () { - const { tx } = await this.underlying.methods['safeTransferFrom(address,address,uint256,bytes)']( - initialHolder, - this.token.address, - firstTokenId, - magicWithAddresss(anotherAccount), - { - from: initialHolder, - }, - ); - - await expectEvent.inTransaction(tx, this.token, 'Transfer', { - from: constants.ZERO_ADDRESS, - to: anotherAccount, - tokenId: firstTokenId, - }); - }); }); it('mints a token to from if no data is specified', async function () { From 6d18435098c797bc8c3cfbf51fe10d450a2f6595 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Garc=C3=ADa?= Date: Tue, 14 Feb 2023 17:03:37 -0600 Subject: [PATCH 033/133] Add `RELEASING.md` docs (#3981) Co-authored-by: Francisco Giordano --- .github/workflows/release-cycle.yml | 12 +++++++ CONTRIBUTING.md | 2 ++ RELEASING.md | 55 +++++++++++++++++------------ 3 files changed, 47 insertions(+), 22 deletions(-) diff --git a/.github/workflows/release-cycle.yml b/.github/workflows/release-cycle.yml index 4fe09a4eb..1831bd519 100644 --- a/.github/workflows/release-cycle.yml +++ b/.github/workflows/release-cycle.yml @@ -1,3 +1,15 @@ +# D: Manual Dispatch +# M: Merge release PR +# C: Commit +# ┌───────────┐ ┌─────────────┐ ┌────────────────┐ +# │Development├──D──►RC-Unreleased│ ┌──►Final-Unreleased│ +# └───────────┘ └─┬─────────▲─┘ │ └─┬────────────▲─┘ +# │ │ │ │ │ +# M C D M C +# │ │ │ │ │ +# ┌▼─────────┴┐ │ ┌▼────────────┴┐ +# │RC-Released├───┘ │Final-Released│ +# └───────────┘ └──────────────┘ name: Release Cycle on: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ecbc2d400..1a44cc27d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -29,6 +29,8 @@ Any non-trivial code contribution must be first discussed with the maintainers i Make sure to read and follow the [engineering guidelines](./GUIDELINES.md). Run linter and tests to make sure your pull request is good before submitting it. +Changelog entries should be added to each pull request by using [Changesets](https://github.com/changesets/changesets/). + When opening the pull request you will be presented with a template and a series of instructions. Read through it carefully and follow all the steps. Expect a review and feedback from the maintainers afterwards. If you're looking for a good place to start, look for issues labelled ["good first issue"](https://github.com/OpenZeppelin/openzeppelin-contracts/labels/good%20first%20issue)! diff --git a/RELEASING.md b/RELEASING.md index f356ab2e4..0318f6338 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -1,36 +1,47 @@ # Releasing -> Visit the documentation for [details about release schedule]. +> Visit the documentation for [details about release schedule](https://docs.openzeppelin.com/contracts/releases-stability). -Start on an up-to-date `master` branch. +OpenZeppelin Contracts uses a fully automated release process that takes care of compiling, packaging, and publishing the library, all of which is carried out in a clean CI environment (GitHub Actions), implemented in the ([`release-cycle`](.github/workflows/release-cycle.yml)) workflow. This helps to reduce the potential for human error and inconsistencies, and ensures that the release process is ongoing and reliable. -Create the release branch with `npm run release start minor`. +## Changesets -Publish a release candidate with `npm run release rc`. +[Changesets](https://github.com/changesets/changesets/) is used as part of our release process for `CHANGELOG.md` management. Each change that is relevant for the codebase is expected to include a changeset. -Publish the final release with `npm run release final`. +## Branching model -Follow the general [OpenZeppelin Contracts release checklist]. +The release cycle happens on release branches called `release-vX.Y`. Each of these branches starts as a release candidate (rc) and is eventually promoted to final. -[details about release schedule]: https://docs.openzeppelin.com/contracts/releases-stability -[OpenZeppelin Contracts release checklist]: https://github.com/OpenZeppelin/code-style/blob/master/RELEASE_CHECKLIST.md +A release branch can be updated with cherry-picked patches from `master`, or may sometimes be committed to directly in the case of old releases. These commits will lead to a new release candidate or a patch increment depending on the state of the release branch. +```mermaid + %%{init: {'gitGraph': {'mainBranchName': 'master'}} }%% + gitGraph + commit id: "Feature A" + commit id: "Feature B" + branch release-vX.Y + commit id: "Start release" + commit id: "Release vX.Y.0-rc.0" -## Merging the release branch + checkout master + commit id: "Feature C" + commit id: "Fix A" -After the final release, the release branch should be merged back into `master`. This merge must not be squashed because it would lose the tagged release commit. Since the GitHub repo is set up to only allow squashed merges, the merge should be done locally and pushed. + checkout release-vX.Y + cherry-pick id: "Fix A" tag: "" + commit id: "Release vX.Y.0-rc.1" + commit id: "Release vX.Y.0" -Make sure to have the latest changes from `upstream` in your local release branch. + checkout master + merge release-vX.Y + commit id: "Feature D" + commit id: "Patch B" + checkout release-vX.Y + cherry-pick id: "Patch B" tag: "" + commit id: "Release vX.Y.1" + + checkout master + merge release-vX.Y + commit id: "Feature E" ``` -git checkout release-vX.Y.Z -git pull upstream -``` - -``` -git checkout master -git merge --no-ff release-vX.Y.Z -git push upstream master -``` - -The release branch can then be deleted on GitHub. From 4e8aa43a900c6fa715c6f64f7c5b6d4d0c041c2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Garc=C3=ADa?= Date: Wed, 15 Feb 2023 15:21:29 -0600 Subject: [PATCH 034/133] Add publishing integrity check after releasing (#4045) Co-authored-by: Francisco --- .github/workflows/release-cycle.yml | 25 +++++++++++++++++++++ scripts/release/workflow/integrity-check.sh | 20 +++++++++++++++++ scripts/release/workflow/pack.sh | 1 + scripts/release/workflow/publish.sh | 2 +- 4 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 scripts/release/workflow/integrity-check.sh diff --git a/.github/workflows/release-cycle.yml b/.github/workflows/release-cycle.yml index 1831bd519..2fd66458d 100644 --- a/.github/workflows/release-cycle.yml +++ b/.github/workflows/release-cycle.yml @@ -142,6 +142,11 @@ jobs: run: bash scripts/release/workflow/pack.sh env: PRERELEASE: ${{ needs.state.outputs.is_prerelease }} + - name: Upload tarball artifact + uses: actions/upload-artifact@v3 + with: + name: ${{ github.ref_name }} + path: ${{ steps.pack.outputs.tarball }} - name: Tag run: npx changeset tag - name: Publish @@ -158,6 +163,26 @@ jobs: PRERELEASE: ${{ needs.state.outputs.is_prerelease }} with: script: await require('./scripts/release/workflow/github-release.js')({ github, context }) + outputs: + tarball_name: ${{ steps.pack.outputs.tarball_name }} + + integrity_check: + needs: publish + name: Tarball Integrity Check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Download tarball artifact + id: artifact + # Replace with actions/upload-artifact@v3 when + # https://github.com/actions/download-artifact/pull/194 gets released + uses: actions/download-artifact@e9ef242655d12993efdcda9058dee2db83a2cb9b + with: + name: ${{ github.ref_name }} + - name: Check integrity + run: bash scripts/release/workflow/integrity-check.sh + env: + TARBALL: ${{ steps.artifact.outputs.download-path }}/${{ needs.publish.outputs.tarball_name }} merge: needs: state diff --git a/scripts/release/workflow/integrity-check.sh b/scripts/release/workflow/integrity-check.sh new file mode 100644 index 000000000..86e99f929 --- /dev/null +++ b/scripts/release/workflow/integrity-check.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +set -euo pipefail + +CHECKSUMS="$RUNNER_TEMP/checksums.txt" + +# Extract tarball content into a tmp directory +tar xf "$TARBALL" -C "$RUNNER_TEMP" + +# Move to extracted directory +cd "$RUNNER_TEMP/package" + +# Checksum all Solidity files +find . -type f -name "*.sol" | xargs shasum > "$CHECKSUMS" + +# Back to directory with git contents +cd "$GITHUB_WORKSPACE/contracts" + +# Check against tarball contents +shasum -c "$CHECKSUMS" diff --git a/scripts/release/workflow/pack.sh b/scripts/release/workflow/pack.sh index 798417d3d..ce30712f8 100644 --- a/scripts/release/workflow/pack.sh +++ b/scripts/release/workflow/pack.sh @@ -20,6 +20,7 @@ dist_tag() { cd contracts TARBALL="$(npm pack | tee /dev/stderr | tail -1)" +echo "tarball_name=$TARBALL" >> $GITHUB_OUTPUT echo "tarball=$(pwd)/$TARBALL" >> $GITHUB_OUTPUT echo "tag=$(dist_tag)" >> $GITHUB_OUTPUT cd .. diff --git a/scripts/release/workflow/publish.sh b/scripts/release/workflow/publish.sh index f9e2802d9..41a9975cb 100644 --- a/scripts/release/workflow/publish.sh +++ b/scripts/release/workflow/publish.sh @@ -15,6 +15,6 @@ delete_tag() { if [ "$TAG" = tmp ]; then delete_tag "$TAG" -elif ["$TAG" = latest ]; then +elif [ "$TAG" = latest ]; then delete_tag next fi From 4ff538af58455987a45243a5ecefca76544969cd Mon Sep 17 00:00:00 2001 From: Francisco Date: Wed, 15 Feb 2023 19:16:22 -0300 Subject: [PATCH 035/133] Fix flaky timestamp tests (#4046) --- .github/workflows/checks.yml | 1 + test/helpers/governance.js | 15 +++++++++------ test/helpers/time.js | 11 ++++++----- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 02664e85c..8bb32dcc3 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -26,6 +26,7 @@ jobs: runs-on: ubuntu-latest env: FORCE_COLOR: 1 + NODE_OPTIONS: --max_old_space_size=4096 GAS: true steps: - uses: actions/checkout@v3 diff --git a/test/helpers/governance.js b/test/helpers/governance.js index ae88e151a..1ffa086cb 100644 --- a/test/helpers/governance.js +++ b/test/helpers/governance.js @@ -115,19 +115,22 @@ class GovernorHelper { : this.governor.castVote(...concatOpts([proposal.id, vote.support], opts)); } - waitForSnapshot(offset = 0) { + async waitForSnapshot(offset = 0) { const proposal = this.currentProposal; - return this.governor.proposalSnapshot(proposal.id).then(timepoint => forward[this.mode](timepoint.addn(offset))); + const timepoint = await this.governor.proposalSnapshot(proposal.id); + return forward[this.mode](timepoint.addn(offset)); } - waitForDeadline(offset = 0) { + async waitForDeadline(offset = 0) { const proposal = this.currentProposal; - return this.governor.proposalDeadline(proposal.id).then(timepoint => forward[this.mode](timepoint.addn(offset))); + const timepoint = await this.governor.proposalDeadline(proposal.id); + return forward[this.mode](timepoint.addn(offset)); } - waitForEta(offset = 0) { + async waitForEta(offset = 0) { const proposal = this.currentProposal; - return this.governor.proposalEta(proposal.id).then(timestamp => forward.timestamp(timestamp.addn(offset))); + const timestamp = await this.governor.proposalEta(proposal.id); + return forward.timestamp(timestamp.addn(offset)); } /** diff --git a/test/helpers/time.js b/test/helpers/time.js index 2e5f6d85a..30df8dc32 100644 --- a/test/helpers/time.js +++ b/test/helpers/time.js @@ -1,16 +1,17 @@ -const { time } = require('@openzeppelin/test-helpers'); +const ozHelpers = require('@openzeppelin/test-helpers'); +const helpers = require('@nomicfoundation/hardhat-network-helpers'); module.exports = { clock: { - blocknumber: () => web3.eth.getBlock('latest').then(block => block.number), - timestamp: () => web3.eth.getBlock('latest').then(block => block.timestamp), + blocknumber: () => helpers.time.latestBlock(), + timestamp: () => helpers.time.latest(), }, clockFromReceipt: { blocknumber: receipt => Promise.resolve(receipt.blockNumber), timestamp: receipt => web3.eth.getBlock(receipt.blockNumber).then(block => block.timestamp), }, forward: { - blocknumber: time.advanceBlockTo, - timestamp: time.increaseTo, + blocknumber: ozHelpers.time.advanceBlockTo, + timestamp: helpers.time.increaseTo, }, }; From 5e76b2622546a2e42e5c19e4ce1a96ee2691c7fe Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Thu, 16 Feb 2023 14:33:56 -0300 Subject: [PATCH 036/133] Add Subgraphs to docs sidebar --- docs/modules/ROOT/nav.adoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index 6604c2de5..fd206aacd 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -19,3 +19,5 @@ * xref:crosschain.adoc[Crosschain] * xref:utilities.adoc[Utilities] + +* xref:subgraphs::index.adoc[Subgraphs] From d5d9d4bd3db23444a06bd1a5e2f33fc81e143795 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Fri, 17 Feb 2023 03:35:43 +0100 Subject: [PATCH 037/133] Simplify ERC721Wrapper.depositFor to save gas (#4048) --- .../token/ERC721/extensions/ERC721Wrapper.sol | 23 ++++++------- .../ERC721/extensions/ERC721Wrapper.test.js | 34 +------------------ 2 files changed, 12 insertions(+), 45 deletions(-) diff --git a/contracts/token/ERC721/extensions/ERC721Wrapper.sol b/contracts/token/ERC721/extensions/ERC721Wrapper.sol index f10d55564..83e59ce88 100644 --- a/contracts/token/ERC721/extensions/ERC721Wrapper.sol +++ b/contracts/token/ERC721/extensions/ERC721Wrapper.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.0; import "../ERC721.sol"; -import "../utils/ERC721Holder.sol"; /** * @dev Extension of the ERC721 token contract to support token wrapping. @@ -14,7 +13,7 @@ import "../utils/ERC721Holder.sol"; * * _Available since v4.9.0_ */ -abstract contract ERC721Wrapper is ERC721, ERC721Holder { +abstract contract ERC721Wrapper is ERC721, IERC721Receiver { IERC721 private immutable _underlying; constructor(IERC721 underlyingToken) { @@ -25,11 +24,15 @@ abstract contract ERC721Wrapper is ERC721, ERC721Holder { * @dev Allow a user to deposit underlying tokens and mint the corresponding tokenIds. */ function depositFor(address account, uint256[] memory tokenIds) public virtual returns (bool) { - bytes memory data = abi.encodePacked(account); - uint256 length = tokenIds.length; for (uint256 i = 0; i < length; ++i) { - underlying().safeTransferFrom(_msgSender(), address(this), tokenIds[i], data); + uint256 tokenId = tokenIds[i]; + + // This is an "unsafe" transfer that doesn't call any hook on the receiver. With underlying() being trusted + // (by design of this contract) and no other contracts expected to be called from there, we are safe. + // slither-disable-next-line reentrancy-no-eth + underlying().transferFrom(_msgSender(), address(this), tokenId); + _safeMint(account, tokenId); } return true; @@ -64,16 +67,12 @@ abstract contract ERC721Wrapper is ERC721, ERC721Holder { * for recovering in that scenario. */ function onERC721Received( - address operator, + address, address from, uint256 tokenId, - bytes memory data - ) public override returns (bytes4) { + bytes memory + ) public virtual override returns (bytes4) { require(address(underlying()) == _msgSender(), "ERC721Wrapper: caller is not underlying"); - if (data.length > 0) { - require(data.length == 20 && operator == address(this), "ERC721Wrapper: Invalid data format"); - from = address(bytes20(data)); - } _safeMint(from, tokenId); return IERC721Receiver.onERC721Received.selector; } diff --git a/test/token/ERC721/extensions/ERC721Wrapper.test.js b/test/token/ERC721/extensions/ERC721Wrapper.test.js index 0558dfa37..6e46d2e5a 100644 --- a/test/token/ERC721/extensions/ERC721Wrapper.test.js +++ b/test/token/ERC721/extensions/ERC721Wrapper.test.js @@ -242,39 +242,7 @@ contract('ERC721Wrapper', function (accounts) { ); }); - describe('when data length is > 0', function () { - it('reverts with arbitrary data', async function () { - await expectRevert( - this.underlying.methods['safeTransferFrom(address,address,uint256,bytes)']( - initialHolder, - this.token.address, - firstTokenId, - '0x0123', - { - from: initialHolder, - }, - ), - 'ERC721Wrapper: Invalid data format', - ); - }); - - it('reverts with correct data from an untrusted operator', async function () { - await expectRevert( - this.underlying.methods['safeTransferFrom(address,address,uint256,bytes)']( - initialHolder, - this.token.address, - firstTokenId, - anotherAccount, - { - from: initialHolder, - }, - ), - 'ERC721Wrapper: Invalid data format', - ); - }); - }); - - it('mints a token to from if no data is specified', async function () { + it('mints a token to from', async function () { const { tx } = await this.underlying.safeTransferFrom(initialHolder, this.token.address, firstTokenId, { from: initialHolder, }); From d64d7aa5d1dac7dd7bf60dae917e400120340002 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Fri, 17 Feb 2023 10:08:31 +0100 Subject: [PATCH 038/133] ERC4626 inflation attack mitigation (#3979) Co-authored-by: Francisco --- .changeset/perfect-insects-listen.md | 5 + contracts/mocks/token/ERC4626DecimalsMock.sol | 33 - contracts/mocks/token/ERC4626OffsetMock.sol | 17 + contracts/token/ERC20/extensions/ERC4626.sol | 75 +- .../modules/ROOT/images/erc4626-attack-3a.png | Bin 0 -> 60433 bytes .../modules/ROOT/images/erc4626-attack-3b.png | Bin 0 -> 66184 bytes docs/modules/ROOT/images/erc4626-attack-6.png | Bin 0 -> 56290 bytes docs/modules/ROOT/images/erc4626-attack.png | Bin 0 -> 58886 bytes docs/modules/ROOT/images/erc4626-deposit.png | Bin 0 -> 115497 bytes docs/modules/ROOT/images/erc4626-mint.png | Bin 0 -> 112787 bytes .../ROOT/images/erc4626-rate-linear.png | Bin 0 -> 50813 bytes .../ROOT/images/erc4626-rate-loglog.png | Bin 0 -> 72818 bytes .../ROOT/images/erc4626-rate-loglogext.png | Bin 0 -> 109923 bytes docs/modules/ROOT/nav.adoc | 1 + docs/modules/ROOT/pages/erc4626.adoc | 193 +++++ test/token/ERC20/extensions/ERC4626.t.sol | 18 - test/token/ERC20/extensions/ERC4626.test.js | 772 +++++++++--------- test/utils/math/Math.t.sol | 2 +- 18 files changed, 628 insertions(+), 488 deletions(-) create mode 100644 .changeset/perfect-insects-listen.md delete mode 100644 contracts/mocks/token/ERC4626DecimalsMock.sol create mode 100644 contracts/mocks/token/ERC4626OffsetMock.sol create mode 100644 docs/modules/ROOT/images/erc4626-attack-3a.png create mode 100644 docs/modules/ROOT/images/erc4626-attack-3b.png create mode 100644 docs/modules/ROOT/images/erc4626-attack-6.png create mode 100644 docs/modules/ROOT/images/erc4626-attack.png create mode 100644 docs/modules/ROOT/images/erc4626-deposit.png create mode 100644 docs/modules/ROOT/images/erc4626-mint.png create mode 100644 docs/modules/ROOT/images/erc4626-rate-linear.png create mode 100644 docs/modules/ROOT/images/erc4626-rate-loglog.png create mode 100644 docs/modules/ROOT/images/erc4626-rate-loglogext.png create mode 100644 docs/modules/ROOT/pages/erc4626.adoc diff --git a/.changeset/perfect-insects-listen.md b/.changeset/perfect-insects-listen.md new file mode 100644 index 000000000..9e60120ed --- /dev/null +++ b/.changeset/perfect-insects-listen.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': minor +--- + +`ERC4626`: Add mitigation to the inflation attack through virtual shares and assets. diff --git a/contracts/mocks/token/ERC4626DecimalsMock.sol b/contracts/mocks/token/ERC4626DecimalsMock.sol deleted file mode 100644 index 9cce5139c..000000000 --- a/contracts/mocks/token/ERC4626DecimalsMock.sol +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.0; - -import "../../token/ERC20/extensions/ERC4626.sol"; - -abstract contract ERC4626DecimalsMock is ERC4626 { - using Math for uint256; - - uint8 private immutable _decimals; - - constructor(uint8 decimals_) { - _decimals = decimals_; - } - - function decimals() public view virtual override returns (uint8) { - return _decimals; - } - - function _initialConvertToShares( - uint256 assets, - Math.Rounding rounding - ) internal view virtual override returns (uint256 shares) { - return assets.mulDiv(10 ** decimals(), 10 ** super.decimals(), rounding); - } - - function _initialConvertToAssets( - uint256 shares, - Math.Rounding rounding - ) internal view virtual override returns (uint256 assets) { - return shares.mulDiv(10 ** super.decimals(), 10 ** decimals(), rounding); - } -} diff --git a/contracts/mocks/token/ERC4626OffsetMock.sol b/contracts/mocks/token/ERC4626OffsetMock.sol new file mode 100644 index 000000000..6e270ca73 --- /dev/null +++ b/contracts/mocks/token/ERC4626OffsetMock.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../token/ERC20/extensions/ERC4626.sol"; + +abstract contract ERC4626OffsetMock is ERC4626 { + uint8 private immutable _offset; + + constructor(uint8 offset_) { + _offset = offset_; + } + + function _decimalsOffset() internal view virtual override returns (uint8) { + return _offset; + } +} diff --git a/contracts/token/ERC20/extensions/ERC4626.sol b/contracts/token/ERC20/extensions/ERC4626.sol index 663377dad..16656bd4f 100644 --- a/contracts/token/ERC20/extensions/ERC4626.sol +++ b/contracts/token/ERC20/extensions/ERC4626.sol @@ -17,28 +17,48 @@ import "../../../utils/math/Math.sol"; * the ERC20 standard. Any additional extensions included along it would affect the "shares" token represented by this * contract and not the "assets" token which is an independent contract. * - * CAUTION: When the vault is empty or nearly empty, deposits are at high risk of being stolen through frontrunning with - * a "donation" to the vault that inflates the price of a share. This is variously known as a donation or inflation + * [CAUTION] + * ==== + * In empty (or nearly empty) ERC-4626 vaults, deposits are at high risk of being stolen through frontrunning + * with a "donation" to the vault that inflates the price of a share. This is variously known as a donation or inflation * attack and is essentially a problem of slippage. Vault deployers can protect against this attack by making an initial * deposit of a non-trivial amount of the asset, such that price manipulation becomes infeasible. Withdrawals may - * similarly be affected by slippage. Users can protect against this attack as well unexpected slippage in general by + * similarly be affected by slippage. Users can protect against this attack as well as unexpected slippage in general by * verifying the amount received is as expected, using a wrapper that performs these checks such as * https://github.com/fei-protocol/ERC4626#erc4626router-and-base[ERC4626Router]. * + * Since v4.9, this implementation uses virtual assets and shares to mitigate that risk. The `_decimalsOffset()` + * corresponds to an offset in the decimal representation between the underlying asset's decimals and the vault + * decimals. This offset also determines the rate of virtual shares to virtual assets in the vault, which itself + * determines the initial exchange rate. While not fully preventing the attack, analysis shows that the default offset + * (0) makes it non-profitable, as a result of the value being captured by the virtual shares (out of the attacker's + * donation) matching the attacker's expected gains. With a larger offset, the attack becomes orders of magnitude more + * expensive than it is profitable. More details about the underlying math can be found + * xref:erc4626.adoc#inflation-attack[here]. + * + * The drawback of this approach is that the virtual shares do capture (a very small) part of the value being accrued + * to the vault. Also, if the vault experiences losses, the users try to exit the vault, the virtual shares and assets + * will cause the first user to exit to experience reduced losses in detriment to the last users that will experience + * bigger losses. Developers willing to revert back to the pre-v4.9 behavior just need to override the + * `_convertToShares` and `_convertToAssets` functions. + * + * To learn more, check out our xref:ROOT:erc4626.adoc[ERC-4626 guide]. + * ==== + * * _Available since v4.7._ */ abstract contract ERC4626 is ERC20, IERC4626 { using Math for uint256; IERC20 private immutable _asset; - uint8 private immutable _decimals; + uint8 private immutable _underlyingDecimals; /** * @dev Set the underlying asset contract. This must be an ERC20-compatible contract (ERC20 or ERC777). */ constructor(IERC20 asset_) { (bool success, uint8 assetDecimals) = _tryGetAssetDecimals(asset_); - _decimals = success ? assetDecimals : super.decimals(); + _underlyingDecimals = success ? assetDecimals : 18; _asset = asset_; } @@ -65,7 +85,7 @@ abstract contract ERC4626 is ERC20, IERC4626 { * See {IERC20Metadata-decimals}. */ function decimals() public view virtual override(IERC20Metadata, ERC20) returns (uint8) { - return _decimals; + return _underlyingDecimals + _decimalsOffset(); } /** @dev See {IERC4626-asset}. */ @@ -90,7 +110,7 @@ abstract contract ERC4626 is ERC20, IERC4626 { /** @dev See {IERC4626-maxDeposit}. */ function maxDeposit(address) public view virtual override returns (uint256) { - return _isVaultHealthy() ? type(uint256).max : 0; + return type(uint256).max; } /** @dev See {IERC4626-maxMint}. */ @@ -179,44 +199,14 @@ abstract contract ERC4626 is ERC20, IERC4626 { * would represent an infinite amount of shares. */ function _convertToShares(uint256 assets, Math.Rounding rounding) internal view virtual returns (uint256) { - uint256 supply = totalSupply(); - return - (assets == 0 || supply == 0) - ? _initialConvertToShares(assets, rounding) - : assets.mulDiv(supply, totalAssets(), rounding); - } - - /** - * @dev Internal conversion function (from assets to shares) to apply when the vault is empty. - * - * NOTE: Make sure to keep this function consistent with {_initialConvertToAssets} when overriding it. - */ - function _initialConvertToShares( - uint256 assets, - Math.Rounding /*rounding*/ - ) internal view virtual returns (uint256 shares) { - return assets; + return assets.mulDiv(totalSupply() + 10 ** _decimalsOffset(), totalAssets() + 1, rounding); } /** * @dev Internal conversion function (from shares to assets) with support for rounding direction. */ function _convertToAssets(uint256 shares, Math.Rounding rounding) internal view virtual returns (uint256) { - uint256 supply = totalSupply(); - return - (supply == 0) ? _initialConvertToAssets(shares, rounding) : shares.mulDiv(totalAssets(), supply, rounding); - } - - /** - * @dev Internal conversion function (from shares to assets) to apply when the vault is empty. - * - * NOTE: Make sure to keep this function consistent with {_initialConvertToShares} when overriding it. - */ - function _initialConvertToAssets( - uint256 shares, - Math.Rounding /*rounding*/ - ) internal view virtual returns (uint256) { - return shares; + return shares.mulDiv(totalAssets() + 1, totalSupply() + 10 ** _decimalsOffset(), rounding); } /** @@ -262,10 +252,7 @@ abstract contract ERC4626 is ERC20, IERC4626 { emit Withdraw(caller, receiver, owner, assets, shares); } - /** - * @dev Checks if vault is "healthy" in the sense of having assets backing the circulating shares. - */ - function _isVaultHealthy() private view returns (bool) { - return totalAssets() > 0 || totalSupply() == 0; + function _decimalsOffset() internal view virtual returns (uint8) { + return 0; } } diff --git a/docs/modules/ROOT/images/erc4626-attack-3a.png b/docs/modules/ROOT/images/erc4626-attack-3a.png new file mode 100644 index 0000000000000000000000000000000000000000..4cb52237d635f634085d87337322ac5e0741ff01 GIT binary patch literal 60433 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¨> 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 W72fFO~av*&4wv-#`&9xxJ7DPz*Q3{XF6KYttW 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 ZvU7})GO|xKx>5WWyCiin@%)Vk{~s{kR%ZYJ literal 0 HcmV?d00001 diff --git a/docs/modules/ROOT/images/erc4626-attack-6.png b/docs/modules/ROOT/images/erc4626-attack-6.png new file mode 100644 index 0000000000000000000000000000000000000000..1587fb5c1360e59243297ebca9f097ed116dcdc4 GIT binary patch literal 56290 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 O?BA=lCt1P7>wf@z+Op{Y literal 0 HcmV?d00001 diff --git a/docs/modules/ROOT/images/erc4626-attack.png b/docs/modules/ROOT/images/erc4626-attack.png new file mode 100644 index 0000000000000000000000000000000000000000..dc059b228bf86b49a55f9afac01baf1188b51904 GIT binary patch literal 58886 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

g*$r>t!O)t#tQ{bjOl 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 literal 0 HcmV?d00001 diff --git a/docs/modules/ROOT/images/erc4626-mint.png b/docs/modules/ROOT/images/erc4626-mint.png new file mode 100644 index 0000000000000000000000000000000000000000..f89ab90070952a0409570d00e2fb6e9ea0ed8c0f GIT binary patch literal 112787 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�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 literal 0 HcmV?d00001 diff --git a/docs/modules/ROOT/images/erc4626-rate-linear.png b/docs/modules/ROOT/images/erc4626-rate-linear.png new file mode 100644 index 0000000000000000000000000000000000000000..09e8045e15abf6b96c089d171635693a60aed60b GIT binary patch literal 50813 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
_8yl~6 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

BP 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 H0c80ad(Q`15Ip#=?z_OZ#$>nl6p`M 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�M8zeDZ}&1+D=A%IIMgIpe~I80@5ZO~$e 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 VEgG)VO%I|lsoS};$B@3d{{y8PI!*up delta 255652 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%0Dmu(TMqrK4N+HQ*K(LrjJqp=6bmLE6%w-{ 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 z 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 From f7b236dca87865752f20585e532c0bffa3fe39d1 Mon Sep 17 00:00:00 2001 From: Francisco Date: Wed, 10 May 2023 20:58:56 +0100 Subject: [PATCH 129/133] Configure Codespell to check hidden files (#4236) --- .changeset/tender-needles-dance.md | 2 +- .github/workflows/checks.yml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.changeset/tender-needles-dance.md b/.changeset/tender-needles-dance.md index 04d1784a4..75ce9fbf8 100644 --- a/.changeset/tender-needles-dance.md +++ b/.changeset/tender-needles-dance.md @@ -2,6 +2,6 @@ 'openzeppelin-solidity': minor --- -`ERC20Wrapper`: self wrapping and deposit by the wrapper itself are now explicitelly forbiden. +`ERC20Wrapper`: self wrapping and deposit by the wrapper itself are now explicitly forbidden. commit: 3214f6c25 diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 1f03aa38c..ec17fa2f7 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -109,5 +109,6 @@ jobs: - name: Run CodeSpell uses: codespell-project/actions-codespell@v2.0 with: + check_hidden: true check_filenames: true skip: package-lock.json,*.pdf From 3e1b25a5cf3be6671014ebb61a716669890bab4a Mon Sep 17 00:00:00 2001 From: Francisco Date: Wed, 10 May 2023 21:08:05 +0100 Subject: [PATCH 130/133] Clean up pending admin schedule on renounce in DefaultAdminRules (#4230) --- .changeset/loud-wolves-promise.md | 5 +++++ contracts/access/AccessControlDefaultAdminRules.sol | 1 + test/access/AccessControl.behavior.js | 7 +++++-- 3 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 .changeset/loud-wolves-promise.md diff --git a/.changeset/loud-wolves-promise.md b/.changeset/loud-wolves-promise.md new file mode 100644 index 000000000..544b52c5f --- /dev/null +++ b/.changeset/loud-wolves-promise.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': patch +--- + +`AccessControlDefaultAdminRules`: Clean up pending admin schedule on renounce. diff --git a/contracts/access/AccessControlDefaultAdminRules.sol b/contracts/access/AccessControlDefaultAdminRules.sol index 6cdda81a1..33ad56e40 100644 --- a/contracts/access/AccessControlDefaultAdminRules.sol +++ b/contracts/access/AccessControlDefaultAdminRules.sol @@ -112,6 +112,7 @@ abstract contract AccessControlDefaultAdminRules is IAccessControlDefaultAdminRu newDefaultAdmin == address(0) && _isScheduleSet(schedule) && _hasSchedulePassed(schedule), "AccessControl: only can renounce in two delayed steps" ); + delete _pendingDefaultAdminSchedule; } super.renounceRole(role, account); } diff --git a/test/access/AccessControl.behavior.js b/test/access/AccessControl.behavior.js index 49ab44b58..e7a91957e 100644 --- a/test/access/AccessControl.behavior.js +++ b/test/access/AccessControl.behavior.js @@ -267,7 +267,7 @@ function shouldBehaveLikeAccessControlDefaultAdminRules(errorPrefix, delay, defa [0, 'exactly when'], [1, 'after'], ]) { - it(`returns pending admin and delay ${tag} delay schedule passes if not accepted`, async function () { + it(`returns pending admin and schedule ${tag} it passes if not accepted`, async function () { // Wait until schedule + fromSchedule const { schedule: firstSchedule } = await this.accessControl.pendingDefaultAdmin(); await time.setNextBlockTimestamp(firstSchedule.toNumber() + fromSchedule); @@ -279,7 +279,7 @@ function shouldBehaveLikeAccessControlDefaultAdminRules(errorPrefix, delay, defa }); } - it('returns 0 after delay schedule passes and the transfer was accepted', async function () { + it('returns 0 after schedule passes and the transfer was accepted', async function () { // Wait after schedule const { schedule: firstSchedule } = await this.accessControl.pendingDefaultAdmin(); await time.setNextBlockTimestamp(firstSchedule.addn(1)); @@ -660,6 +660,9 @@ function shouldBehaveLikeAccessControlDefaultAdminRules(errorPrefix, delay, defa account: defaultAdmin, }); expect(await this.accessControl.owner()).to.equal(constants.ZERO_ADDRESS); + const { newAdmin, schedule } = await this.accessControl.pendingDefaultAdmin(); + expect(newAdmin).to.eq(ZERO_ADDRESS); + expect(schedule).to.be.bignumber.eq(ZERO); }); it('allows to recover access using the internal _grantRole', async function () { From f355bd3a2a4969a78cb20ab721a1cd2b3c6da4c9 Mon Sep 17 00:00:00 2001 From: Francisco Date: Thu, 11 May 2023 17:41:02 +0100 Subject: [PATCH 131/133] Prevent attempt to publish to npm (#4239) --- package-lock.json | 13 +++++++------ package.json | 1 + scripts/release/workflow/state.js | 14 +++++++++++--- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6611223fe..139ce68e9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48,6 +48,7 @@ "solidity-ast": "^0.4.25", "solidity-coverage": "^0.8.0", "solidity-docgen": "^0.6.0-beta.29", + "undici": "^5.22.1", "web3": "^1.3.0", "yargs": "^17.0.0" } @@ -15175,9 +15176,9 @@ "dev": true }, "node_modules/undici": { - "version": "5.22.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.0.tgz", - "integrity": "sha512-fR9RXCc+6Dxav4P9VV/sp5w3eFiSdOjJYsbtWfd4s5L5C4ogyuVpdKIVHeW0vV1MloM65/f7W45nR9ZxwVdyiA==", + "version": "5.22.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.1.tgz", + "integrity": "sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==", "dev": true, "dependencies": { "busboy": "^1.6.0" @@ -27985,9 +27986,9 @@ "dev": true }, "undici": { - "version": "5.22.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.0.tgz", - "integrity": "sha512-fR9RXCc+6Dxav4P9VV/sp5w3eFiSdOjJYsbtWfd4s5L5C4ogyuVpdKIVHeW0vV1MloM65/f7W45nR9ZxwVdyiA==", + "version": "5.22.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.1.tgz", + "integrity": "sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==", "dev": true, "requires": { "busboy": "^1.6.0" diff --git a/package.json b/package.json index 8ef2738b5..b198a0823 100644 --- a/package.json +++ b/package.json @@ -89,6 +89,7 @@ "solidity-ast": "^0.4.25", "solidity-coverage": "^0.8.0", "solidity-docgen": "^0.6.0-beta.29", + "undici": "^5.22.1", "web3": "^1.3.0", "yargs": "^17.0.0" } diff --git a/scripts/release/workflow/state.js b/scripts/release/workflow/state.js index 4d905e260..5cfaafb86 100644 --- a/scripts/release/workflow/state.js +++ b/scripts/release/workflow/state.js @@ -1,7 +1,8 @@ const { readPreState } = require('@changesets/pre'); const { default: readChangesets } = require('@changesets/read'); const { join } = require('path'); -const { version } = require(join(__dirname, '../../../package.json')); +const { fetch } = require('undici'); +const { version, name: packageName } = require(join(__dirname, '../../../contracts/package.json')); module.exports = async ({ github, context, core }) => { const state = await getState({ github, context, core }); @@ -34,8 +35,8 @@ function shouldRunChangesets({ isReleaseBranch, isPush, isWorkflowDispatch, botR return (isReleaseBranch && isPush) || (isReleaseBranch && isWorkflowDispatch && botRun); } -function shouldRunPublish({ isReleaseBranch, isPush, hasPendingChangesets }) { - return isReleaseBranch && isPush && !hasPendingChangesets; +function shouldRunPublish({ isReleaseBranch, isPush, hasPendingChangesets, isPublishedOnNpm }) { + return isReleaseBranch && isPush && !hasPendingChangesets && !isPublishedOnNpm; } function shouldRunMerge({ @@ -80,6 +81,8 @@ async function getState({ github, context, core }) { state.prBackExists = prs.length === 0; + state.isPublishedOnNpm = await isPublishedOnNpm(packageName, version); + // Log every state value in debug mode if (core.isDebug()) for (const [key, value] of Object.entries(state)) core.debug(`${key}: ${value}`); @@ -102,3 +105,8 @@ async function readChangesetState(cwd = process.cwd()) { changesets, }; } + +async function isPublishedOnNpm(package, version) { + const res = await fetch(`https://registry.npmjs.com/${package}/${version}`); + return res.ok; +} From 3ec4307c8a79ddfee9bbaf1f26435c908fae0cae Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Thu, 11 May 2023 19:17:06 +0200 Subject: [PATCH 132/133] Fix bug allowing anyone to cancel an admin renounce (#4238) Co-authored-by: Francisco Giordano --- .../access/AccessControlDefaultAdminRules.sol | 4 ++-- test/access/AccessControl.behavior.js | 24 +++++++++++-------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/contracts/access/AccessControlDefaultAdminRules.sol b/contracts/access/AccessControlDefaultAdminRules.sol index 33ad56e40..07a5b4f70 100644 --- a/contracts/access/AccessControlDefaultAdminRules.sol +++ b/contracts/access/AccessControlDefaultAdminRules.sol @@ -106,7 +106,7 @@ abstract contract AccessControlDefaultAdminRules is IAccessControlDefaultAdminRu * non-administrated role. */ function renounceRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) { - if (role == DEFAULT_ADMIN_ROLE) { + if (role == DEFAULT_ADMIN_ROLE && account == defaultAdmin()) { (address newDefaultAdmin, uint48 schedule) = pendingDefaultAdmin(); require( newDefaultAdmin == address(0) && _isScheduleSet(schedule) && _hasSchedulePassed(schedule), @@ -138,7 +138,7 @@ abstract contract AccessControlDefaultAdminRules is IAccessControlDefaultAdminRu * @dev See {AccessControl-_revokeRole}. */ function _revokeRole(bytes32 role, address account) internal virtual override { - if (role == DEFAULT_ADMIN_ROLE && account == _currentDefaultAdmin) { + if (role == DEFAULT_ADMIN_ROLE && account == defaultAdmin()) { delete _currentDefaultAdmin; } super._revokeRole(role, account); diff --git a/test/access/AccessControl.behavior.js b/test/access/AccessControl.behavior.js index e7a91957e..3e61616a7 100644 --- a/test/access/AccessControl.behavior.js +++ b/test/access/AccessControl.behavior.js @@ -621,14 +621,15 @@ function shouldBehaveLikeAccessControlDefaultAdminRules(errorPrefix, delay, defa }); describe('renounces admin', function () { + let expectedSchedule; let delayPassed; + let delayNotPassed; beforeEach(async function () { await this.accessControl.beginDefaultAdminTransfer(constants.ZERO_ADDRESS, { from: defaultAdmin }); - delayPassed = web3.utils - .toBN(await time.latest()) - .add(delay) - .addn(1); + expectedSchedule = web3.utils.toBN(await time.latest()).add(delay); + delayNotPassed = expectedSchedule; + delayPassed = expectedSchedule.addn(1); }); it('reverts if caller is not default admin', async function () { @@ -639,6 +640,15 @@ function shouldBehaveLikeAccessControlDefaultAdminRules(errorPrefix, delay, defa ); }); + it("renouncing the admin role when not an admin doesn't affect the schedule", async function () { + await time.setNextBlockTimestamp(delayPassed); + await this.accessControl.renounceRole(DEFAULT_ADMIN_ROLE, other, { from: other }); + + const { newAdmin, schedule } = await this.accessControl.pendingDefaultAdmin(); + expect(newAdmin).to.equal(constants.ZERO_ADDRESS); + expect(schedule).to.be.bignumber.equal(expectedSchedule); + }); + it('keeps defaultAdmin consistent with hasRole if another non-defaultAdmin user renounces the DEFAULT_ADMIN_ROLE', async function () { await time.setNextBlockTimestamp(delayPassed); @@ -677,12 +687,6 @@ function shouldBehaveLikeAccessControlDefaultAdminRules(errorPrefix, delay, defa }); describe('schedule not passed', function () { - let delayNotPassed; - - beforeEach(function () { - delayNotPassed = delayPassed.subn(1); - }); - for (const [fromSchedule, tag] of [ [-1, 'less'], [0, 'equal'], From 1642b6639b93e3b97be163d49827e1f56b81ca11 Mon Sep 17 00:00:00 2001 From: Francisco Date: Fri, 12 May 2023 18:22:26 +0100 Subject: [PATCH 133/133] Reduce frequency of version comment updates (#4244) --- scripts/release/update-comment.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/release/update-comment.js b/scripts/release/update-comment.js index eb9f937ca..9d6df2694 100755 --- a/scripts/release/update-comment.js +++ b/scripts/release/update-comment.js @@ -16,7 +16,7 @@ const { version } = require('../../package.json'); const [tag] = run('git', 'tag') .split(/\r?\n/) .filter(semver.coerce) // check version can be processed - .filter(v => semver.lt(semver.coerce(v), version)) // only consider older tags, ignore current prereleases + .filter(v => semver.satisfies(v, `< ${version}`)) // ignores prereleases unless currently a prerelease .sort(semver.rcompare); // Ordering tag → HEAD is important here.

XRhnQ}H08>D;q7lu(1A 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 literal 0 HcmV?d00001 diff --git a/docs/modules/ROOT/images/erc4626-rate-loglogext.png b/docs/modules/ROOT/images/erc4626-rate-loglogext.png new file mode 100644 index 0000000000000000000000000000000000000000..127bc7f2fddc37bcfd0863238db2c7874f4e210f GIT binary patch literal 109923 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�S;#YCJ>3E4Gp0$=R%K*`_zT?& z0-ZxnwwzRPywb16+oI$JM@1llN)rv;zB}g&$g2Pjqf_JvB8T=OE;s`)`&TPcu327t8xEeO1ZMeJ77e9@~F*J zv0WRU&=vMRhplNp4Iuw-v4PdJO|6j&ztrf&MR?BrwcXcSX439ESiF|ZlY?30P^^J& z5T$PyP39{_4r!a1-$_>pVKzpcu($RbtLLK*mi)2*-w$oJNBD zE_0d?%|4gqb(?S&ojmQv6X?tx?>70}%I8q%pP^SA_T^Rv| z_!?D#Lp>X>rNBPSi;eF!+Au`Vu&z;Vu}=Bry&4iw{F1Qnjr_t11%8wa_4WIW?Po(* zOmI_$u2P4{*$VsVhJ`X1f z-4|QplsNOJmkDID*G0%aVx}ygv7}95Ze9o#WgVyFm5{<8x+oMQH@t$syf!ME%xwd+`4>sAdTg8Z<6LE(>^PtHgfwtzC)hA;< z31)`FuC^t7CGz^2juNXmRoR`CM!kcdwP1dp2yx0lOwnT}bwB7mxe`VBKxF3QUINBC zN0AS8(o5mWYxoXSPh=HSKNh~W4E^@iYkdyqoke8ApNnU>sbd%IDYe8eTfY3ac)5#j z+wbqpJK}lLJG|2|v5$&N-{9(6*YP`O*+w(gg=br`IhZc~eUFRH=6LerN z5+ng5{fB&8ivqle4PI~L+WqY%8m8OW{_vBAzi(33Nq1%I$?%iZoGPyM%`@gH`YO+V z4&Zr{)AiEEaTlo5q$Tx;Gxl+jaONCC4VBpU5n&DNizN|@E_^r;w z`TYD~;4ggMZ-;2s=x09uwKH zQM9a_wJW{lX$4i}>JoQy)uImc1I?N`Ir}faxM#DS`=$Y{l3yFpCl+p4!g^eMJd|x!FDAhrs}sIShN%taH1<@ zCv$hBP=lv8BPO6_FkguOHZ_%j;_HrJ(O;@e2<>S)JKjSc>7OEylE!);VoYq_7|S%k zfQnELeKSPmwk9=amohH#WH+&d63)=aH`XmA|MUpVs!7OHg6aOIRg#;me*MreD%bZ> z6Er2o-?@_;I=a&Op|h?v21>k+redJlkusk<(rLjWzIrxQ-SR6&VD_sEGj;BwRKv6I zh2N@7!gL?%0v&31El~oxp2=SprQ-Cu-!u>QgfpDf0Nb6^s@CsappzUADZT@FnC$j$ z6Bla6G^K?Jt@~9bz6ZfOO%~b?;}V1ye{R0{mn|=>g)c&qF`6Fdn_wH)%@b3h2t82&!CGEYRuWiigqj&grmtNs{AF>MaL~O#NsA;>> z@0e7IC5E-h`*F5w(mbR^!n}7=+p11vFsr{ZWqg_&?5?~KkQ*C_Z}Bh4z##a{E_&4b zR!nAa>|cdRuX96MSKN3sr71w%pV8WhLyL z)YDFvx7!~Xb-~AMm0{lwP}bL2;b7o=z_9dba@`vhVUw2_uiD&eFQr;sSs9%GUdD^) zlGDvDKQs$UX<6ssl}_pP5KQ9;ow3I^c969ij9@vTCaQ>FA(MTv+U;;Js}1dO05!FA zd5;1(m{C(#i6J1ywYKAluhLuBo(TDNoUlCC_mJ-#lxaml8u@9lO3zlpMD}WQHug^q z2yxtZ_fY+0)oBd|DGYCpLdbsP{Dp;cPdlLrq)>8GuW-JJP|cld6^$aGTS$fu>qc+b zO#AV)<%PTlE+Xz8^Qr1e4iqCN4{l!fA%*Rw6b%tMQQN{`{?EFCfqT8VXXQy01VG{? zqtf+!(dH$5y_SymQyC%AB;&c)sF+*2354VXMXt%CFnsdqYK%=y%+9NfB@j3>v`7Lc z7I@`Snos%zfyGz0seAdiog}p?-`j2_e z<&(};tOZ*Y{!?y|u5L8&JP+u%k`R1+m|?p{Ut)_q=kWlm0VEf}+BzC2Wpz$D9w5oD zdA!_Ut#s$!Oy1EEH5uu2zfp-iWe&oF%Hpgx-m-B{6W~N4Ph~UhweC};XJR;yGd{)# zu30t4(hp3ZJ4WQk>A1k}z(;2wy@9x>LG;oOff*xAFoUfW(4VCk7h)Fp{93m3dTw@j zA|boLVJ|SuNB?MVlW_S~?}t^j%;~nqI_O8i#ui=(gkC%gpj|P;xs99C0)TAy`7CkW zkVV&pl_4ClAwnEqGa3@8fYbAo_>mD0_DRpE2X-HZ+F9;68)o&KYku}uCkcpmQEe{s zsr`W}%+Tp^^9v5bNH!+Mw`sW=qo}5P7}g(HjlSuQNgYp^L;_y+QYgY|UkldAFzZ$J zOgC@H_)L2x&SKG0rH_WT3*oI8;;{Mi`^c$;2`M=&ahP0QC~|{3_BP zCi0}#TJW4lCXQeqoW*4pYtj-ci=5gB>#@fy>Q)7VD(zce?zlW$={4UXYQ<)X%qts=S76uU`D!^4 zObV{f*Uut4nkpIh#YmDVI1i%6F|BSkW0#&J@Jk^sf0B!M!>`N~Jq+e6eU+TK)95)~ zdDZ@C+}ka9S#>9HvXpa@sn7JX@N%04nENSix@)NFon9>pCPHkTKJ=!xonTc(0z{lr z6&f$HXs~I(J{7G>F7nVwMGAiW*!d^$PoBQ({{hcN7R+QduNMCgTS4T=HNZhnN8_z% z=YotvWF}P5)SPk}XZ*M9XA?bZ3MNNCeWa2?-}opLTe5{y3=UdutdXreHz;>8*3{EO z|8FIOQL%SNUulk`3u>@-vQ$V$Aaj2z>S}bSIdtK;u9*;Z$C;X9lzCKd>}RB^wT=Z1 zZW!gB;Mej^a|eGb*mb)o01#dcl3xRuHBj*=~0=U!1Y1k{iL6p9f*%kiZo1tS^F zyVqPh+n+4s^BqYDhHuS{BQXi_jF9+-G*Nq?A9brtIO6on`*xP!CTBNPsy#{(OH!jv zMAlq0EXL~TH6fX6;?jNiHqltnC31lcI*rV$WS&u8%37Rz!z{&^<7~iE6u#07y1Th5 zPSqn}?`V)Jdv!I^+W^w5g6dARXwV1>&|EQ#Qg;9UBD3Pqy#{I{&>tA}-sz`&nqa_R z&M1&16=+3QdU48^+Aijcb+?NtFYpml!y}cpRvnnxsx;wzC;1t)TcZl)u1BN1vw<2r zRqIP+?*ry_@%s(Rg5={Vd|7KZNE3WVU-UO6PN$$V@Wh4EjXQSOANDt|_N zU}R1(Vahc3&S%RJNGQ0`TQ36>Q=`EThvAG}%;kw2)f3j8A>~4KjV6IhvDOGYFDkfMc-Gl-QHyyaDEt8kN98K;@EDTx5|O8EaxrmmWFVyimFo7ypR)H#bIk(VuRZp4A(xwFfwB%; zt`EuAql|d)_5ZbMsMHvtmP5&8uJj_+q|Jas&AS=*i@=fLcVE*T?$Z5sHV`4RdRZ7< znJ)2V#;?Tq`fuiW4<3n3@VxeQX`QaTO^uDcx5yvMrRni5{&RlTXg8UdO5-Cy|&NQJe7VZ{d48kF9Uo^zt1f-T(s5 zE%NMmdxp@V8lQ(NI*#uRpWi6ALE0gtguaxS>JqwSM!si|kAW)KGw8GY5NMKPyrVRa zcOILY6jJ&!L^-+ac30@+HtBD8BX@e1%U7^@fn7op1d#kS3 z_nQS$+xU>L4e8skVp_R-?)C|~72^T~j6zNl!cnAfUd&^k4~}azr+T@xB?cH1>-!&7 zAa%zmA9g-nO?F1hRBiX1;uZn!-%5-}M4a!@t=<}Y#Qu)QBN5*tq#KZXQUNVM$f1l) z>j2Y+4EeGznT(n=)@KShH$}J+(<98!kuXH+K@c{0PDMqh-JX0cr0Zfe%DjLnn4K9k zrGc=WcIz9=KWga|x~uo`uOcUjc4M;X^BYYY=5D9!p%}7IwhZ5dC4_T<3%aFPn}?wb zq8wSiE}+rSCGrn%C$G1EpC&A_l=3^hea_Zyi38(~!;b;WVD+7@H~+}XPy26}ff2@@ zN!RZ{MnQ?WQqb4YIvS|b?Sy#7tMT}1V*?RJxSCTM957Kv@yOX6Kw&|1I zaG6z7X3yaVC)T$A1g-#WrhGZ zSXF-Pha?x&@WI>Y)|1Lf5grcatU*+2t^PNg|)tBcaR9 zU!e8V<~6<%rxJ=cn1f5^m>~LTzxgp$eUgj-S3!akb9`uc}5z^JPdoP(6Nsl!SJ6yN zPX$Rpm$)=qHpU$w%Rzg5aY7qQuiDxFVcQK)RSo5uSLD4V1U*9I-5OZczzRTTm^Bf| za2l2r63R)J+uKs$e$x>FOtV+m_xA!cj6atXCV6UtxWsraH(hj5JxG+-LMP<~5C{U= zXW+pg^R@dI;0naD_Vyf*fNs}3MaU;e8yfULWe3I~JwN|Ag&yllbaZRUj~RF5H6L-} z{PoMJ$e^h`b7w2mJ1>hJIOu#>)RncakNS-vi%-UZk?>HHF^9u9zb80~HO;y@`Vg&tnR`hE2uuO&$8iQJ{`CcjA=>1Rql>_ zFnA-&A*6~CdXHs}ulo0g4)1B0wQN+&Eu7%mBop!O(Tl%)k*}mMDodW=vkFZn`|p_; z7(x>g4uib8vr#)91VE6>K-qNO%JWB9(*L9=RCC8z{?nk4DgO0IyPy4d>BaC?%8jnr zFCqljodpo;is_b#sNu@;U~fPq9^MM-%ku&8W_1KzW%pb-@!chnLfu`Qa3z#KqT-K5 zK0aXbqJ>R(WB&1bYYVq-mEdn;A^j|^WIVGvHCL49d?abb>&IeD(3>c?P3GIT z#X$;T|2OCCOIptz1@-y85Pz92j$Mm7-(Sn-dCX=A$DT< zH(ncG{e~B7qQolJy{gPT#P95OTL=*9o_%*Xs)G>U0F|tPDNodgkWX-u938GH{m=?^ z(?;E(Q%%$;PX(5rPOUJT#nB}_5k!eTj zv2c<-OCBa_+iVW*;S#uBTkXw!7>S+QIeT0*r-_PSzD?wSyDC3OA5}l#xBlAAPJqI@ zR=!Kdf50F(M=0*$e((8cnpk=GI4P|1?f20cNR!fET|!ofhwkJ z`~DRH0fB36mW?SOCBzLk`26c2VB+OX0+|!N*V%oT?gS_^@l7D|{YSgY>HI8P{Hb5b z@Y_5SA)z=P+0}SVo*cyBB2CymvQB1J-+Dd0x_(mGp`aFoQq%YrYkACZ0M4RL7z=E1|SU1ok^#c{TtXTpKWST53&&j>X#)v$yc` zq2~>0+kw^b|US; zZE`bW;i}_rYc|~@w5Ke7Xe&rflfpZByXmTPr6!82@2 zPbs-JfQXkkEuJNxmlrI+F);p*q36?F5&c_Y>2CQqnh&qtZ%n*1hhnZ5d%ga_hd=iX zRJ#_%&Dj#W^xh&Yr+~FA(;92rLCX;(eDPqpWc*~7I!D!%*>qXC%!X&rF7UZ5;1?B( zgo6b&`qj#2X;!6QxfjUG)E7S)U*MKS(ivi*l}{k|HN8uXGHQJg;5y(c&=`S`OefAJ3f=4bxiS zHL?QkEZx=8Vd>1APquTc2TXe%{U`Q^rOuoRbN1W5lycVfjsKDLj5<#0GlB=Bv!B!q z(bhS>9=d+h$6FMeq&h81C;DkQD4RGZIx<;ESAM``!51d#CB{wh1-71bEtb6Siu@nk z=y2ZSdzf(;wuf0zoQA|?P`0N*y0`t;SKd}edC%XM-`0l@3Q)fmGBD^p%ik$5ewli^ z_GYY}@i|LhO8z=R9wT=Q3lZt9W+=$jXP`SsRc)g_e*BH9>F}Ixj^>VHhRg-%+(obS+<25<`vFgFVeCSob-E)T6Oi!nQl2 z5^zQzY8e<0cB(lu4Oy;74ANur4HF2OO*`mPcvrtI3LR&+<{*)U3V)QA_E8QVj?oS` z;(#+`t`Stro0nzrV4jGP<+F@>&^`S_`S|m_7X)2Ak9vm@J{_Rrw4{Y!0E9W#GL!Uu z=`ydIUV{1Pw1aAf8Zn8Keh_MKL`K@{=(LbG?%1`0hknK}!pOEsU64WJh#T6&|19w~3fOM% zXlM9n-u*1JA!~@i1WtoW2U?!4T| zWEeN>{LkVWR_N}u1dAVB2}d0QlA$u^q=UStA`E#QhAdS-sHAu5<-q0$Ad-HE)+a-^ zTC`d5O?ost|A~`-Uo8~miDIbIth)Wg@<|05OZ0VDU{dwoG;R7hBw%stXKY|bh{lz% zyI66~8CvV=2)+YbND*Uwpo{L_Lmy#Q`vx(7U$_?9L~JMK3_Vrs+k0HCPu(YHjUny} z&n`p3IoZs(E9j{UBNqd}kLq0xxZP1EULPoYYLXt7-o)eyOHSqPfYov?XuEHxqiNW* zESADO%%C!K1d=P#|MN?Ojcm58@|0g1jOYep^TTDa_U948U0zFBw9?nz zR7q~VLm6Tz@($Nb$9tcrqg&B8NydUbdq3;)x$eu&)^vEN&c)CKNMwXmZtrUs1s5Bq zSp9iT9p$?Q_DVxqsC-Jh>Bfq4@1sgn3d^p)9RqFQfiIdF1xMA&Yz$s9A<>ZMQ~(jx z;;X})TXF}E>~Q>$tOmb54qB4OcSyT=^SHZK*KNAtiFvQmSOSj$af`x7W+efpFM8ur zVmPCT0M#>8MVem@UWS2rB)-0-@|3VU{*=-Jx2$Z|Nk+r^*%&KnVbeKX!X&h|?(5% zZGqBL`@bH9QuHmAUo;3m5qdeEZ=gfw*(%f0uN;Od6~e(f!wRs02ERb~JXO)NdoL{b z`ZGVV)YQgD_U9j-%5^kC*WtX#_|m1TrPvU984;r2SR)O_SAPr+y@6loXtKX*{@>k` z(}_?J({Z*&>+ZblOqk6xm2(&qa%ppAdFM&;e<+0FEw9RfR-_cUoH-~SIo`0mc+OoL zHUWNYZnY-D$)T7L?Bo|YnyUaGxXC_SwS5wzQ&2^nhbd*tiNG{&T_T;GfNo-Lv-j}X@RW=OjJ1U+V4e6cJh z^xWc?j-w~Q7b;J7A44e%ij)dpu8+O-EFZAf7nw`e?>ftOW)`PSnysT$F-Slv+{rVH z?fSM75CfqZn%f)mYCB+v6Ucb+QwUZp~pZYVvzZC>*LK#yeRhsUmn7!F5#DT3A6deYDWHIaHwQ11BF~%8SgyXCU#{ZYsEtgne(lS@EL_V zeZScind~l4H2;|^)cSCCX5(Mde>h$zzEKQ9WWQ$>{w>DO>w0{?+XTP7qSqR!tqDl1 zfzDgJv|nZU=b;0RX}9IEU#DVd24~!d;*rL~1znLC;f*;-0}cL6_o;f8yRHBDO7l{D zx+zfgzk-UM;iafm`>2aIJKIr%IX zyFM*{xO6Y*5jv~=gxJ9dzm#-HR@`CfdE-xQrH|-X%Hg+eC;vV}zfZpkLnDsMGn;se zzq~U-J=MQ{xOtgdZ^E*%iaq$X2U4DYM1%z4?Y^!R34f+w1gYYn@dFIJS{?-n8vkG z&Hb%4EKsHXcGQ=KpNjDdRZ78LKK93Z=K_eN98o=z6m!~d96Jr=>Ljp0h*1$OVt`fV z^?-zKpEQnd!USWqeh_zthVaf1bBnI*so!7h*0A20nv;Yni$Kj44v5bQyF)AoWAmT( zG6)=oRi$c7nM*Lykmh`OW2)6O=M=1J+f@d@}UP0GzG~_iyrJ?gkUvfxS_RbUtunpv!ZP>5sO0FKu6ZoRLl=7q5qzZPeP!9{aDTaue9wn*fAp#LeX)ZRwJSLS2ebl? zc{x>de>}_?2MOF4-^~Kw3#DD0mZ04l6{zS)@4A zFK))K4Vj2y_|ocd%4b+r>O~O5q0eiaQ#Mihu@wVhOE@%QQCTV3QGyWHpM$P=a59e+kNGar^kb?1_&!kb@o`InJSDIWX-VVYksr@%^ zRhQW23sL?0K`bRTmR~kbj!dHe>Z?2s=r-|9N+o_<$5b*YETISWwv6Ib^wS^9Y+Ce$ z&0IV&p>slYJJz)i)m!NEm+lWoVJn$SezmS*cSO8XEC{UD)^=6*5IK-5-zUlv@Xb@^ znl(Y!=%C=($LAq?BKs)fmw)H=e)FRM{0Yh{OBc(QZN`>h(#}VU^f&~#BVCT7EfFmd z9ioTFXE^NJq6K^}_Q+Heh{jI7dFQ>`wQ!L^WkoM|0FyD?D`vgdFr=cUHVH~E8w!9A zmB>ONQsPr(W%W z4k3*PZ!{sm-bx5hQ}YqAPX~@BD@(|(q_E?>ZoxUJ{uDiG?b0d_HT%|W?!@2u88QhF zd?#}MBBYf#W`!ScS|khf?8YB zOG;$hlSYcaw?(F9%gk0{Eer3Xlf*q3(;(F$0RVXFxcX~{>6f2v5xmbd{-p+(4hA5e zv0KYB$oq2uXJ_>t_9!p)C)kQl+}39@E0%tLE>1OGPJ3p#MI0NnLfd(n;X>U~i7(v^xa!~SNn1&B?cB3ASj z|LX~#%#jS)u_xSs!MnyRNoQ~CvnTX6yVLZpoQ?i&fMrpRPbq+4JRFQ^q;&uh;b9CP zKKQ%rFj-7=Vwk^=xS479@QzY;fMYK=={+_zg|Mx!PyrQaNg%7yfgVgqYx#Uy1!JSi zD&aSEY*O;60J!>hSv92ahEhxtCc8~d+g&Xpm zlp^d+$J*5CJi1xHbS;@JRs&IixqsmxP0xy8Ww`lbGE?L5hTRj;el|;K*$|1VxEGa; z#<4=AnKeE#dvdGPgsAkl#h979{C66bPkP+Bf4P-AHeL3RMg`!MU#6j!d9dFQoPv3(e?&7>dGd9p(KB#{NHAYi6y(4CkU#Cz?^xRdZn>8sf@V}16NZZ|~t!c>F zDgChHZ&FA7kt_Zz^{>CN(N$&CHkC(<&^vf=H}qei^^=0F)^CALyW>1xw7zQ{zQT;7P>A4%w0<%RrmHJHd8pD8-eIv4JS6lQ< z0w%2_q}mb*_?`?!Zy=941#4(|$p_pxgOpkjK>AejTon;pDBjF+%Yz3l(O6zmTCz(V zX)GJ#j6QlWB7b@zB{p9mmV``vmZ3)aX|WQ6bI)iE%w=yX+ItL?D=2WMNuE|Y6{I%2=Ay-M;Jn?Th#oM0f@7N)bqI)8;I6lvQsw0 zV3r^QYK*;`=(mv!#2??tj7Sr=-J6;(aT;Kv?%*?82}XB;BFsFlpDb*^$6ss8AABiI zwZ>Jo9KF?Vl_+}q#CoTJF7Mcb*$VJ!)a&Qkfo^u!&a9G-?e~Vk?NJiX=Gk#mlflOC zF3qjwqgI5!$q1?E+?QZdKzY$b`_TUEz{3jB;C&QMS7)0}Jn5jsP{R-~%=+is0UK|G zx7BFzCmx^%Bn!yLJUAFOjs24O=1|{%B*NtBJFx&|_5Jv_j@#4=arq_jZ=HaAUo`h9 zxa0n_NIX?0dY?;7e%f2fR}L*chtG%^fkTrNikJT3@c*&()lpeB?cOLzNQZ=!G>C+B zgQT>A2uKM?cQ>e{ba#j}(j5ZQ-5?Fp-3>SJ&E|RDbIv;7`NOrO?mc_rx~`e|1+v1I zgF_{D(tsZ+0UlodJ};tgg(KFMaR7(pTjrBbR=n*REX8^U2bQp@Vh&q}Jb(3qW@4h4tQwSd|vM;$Z zrT`D*UUqX_s%1oiumyrybeElrm1x28Yk-;!y1V&&jVk80bQwZQfUAG1@!b#++cRs|Ro|2gpK z>)_J^<=6bd82tbaE}$O)UFl!9ga4^@$34P_6-tt;j@oR3C8S`Q4gaL)w-QSUUJ@0sRVOks98 zXNc#^IB5WJjdR7RuZwu5%$5#X0njMJ@GYG(V5U5-YWadmVZ#G@O{Sk3dctjq$EfuD z?VPD!=+3|#CO{|n$4EWCtOQt=(w{2`cYMD>`!4Wqb*>1Zi+)J5xdL}AAChqbY!nKs z$ESaJ5UU`d>Z>=K3Otv*_C#Ms&hMoAsXs&T97~X)(pLRZ* zl#1wufM9vN%L}MbvOg-3ZuC~{2?gob1Wd;T5fYTZD@up+pj4$`&EmGKp0&AR zT_%;LY9eS!rk^yZo6?$yKuA@j8LpI-l!ZdWjaTCsTq^Q49)O~KyPjU`qnE^B_0$< zTrJIE*6rvtHG_BE0#Oh&7M{|___$DW`~SNKRl&=ev!AJC3TwKv;TMylv6~QEW=)DQ z)XBLQgMkhiss%YUqBJ^sf7-^60YO75!+Fz7Su?+u7Q91x*!OL9dU;Eh85Ms=!cE;j(mi(1xc6)-}mjeqw5vO!9fUWz#L9W-Q5{3UmVQR1RKic?m zeQQ-S%I>{>xG$V7&=Xqg*w*84OVv(N>i^Z_(W38f_^qp-^ifZce~ocnNQm2S5q~^aFg3Yw!mL##h;?K8gO9J8pKG&ueK-F#$8`wGJ}z6zh9x zyF!z;O-}0z$R`9&-%)gCuP#0(5TOFn7*)|V1N0T`bjHQr*}36*_WOmRK%YLM)< z(02$o;&1tK4AJ~#jmTk<2eggl2n&DPk+ zC2}y7q(o`HGuL)X7H(X7N$w;7G@ot1y*q|f{EeFCT32uCkG3}fiz`q4*qn*4!z;}4 zlX#By?2uiirgf3`uf$f80yVJzk?bWVAq7y)Do{X)gLDygIjLzR9o}|D z40B;`aCyq=+`3&IVD1%gTiB-K76?hMkZ-`-`UOyw zu|ww@Jhfn3sstdd6o~eE9H@pRSf3JUH%A zaWP zab6%XoC3TLx`6kAJu1Y?1D&u45YGVZn1bxqa7hRzkV4yG7TIwGpBSJv1igeIzXsBi zkW!G#Dv&=lhjXQ>ji0Qc^?%f)(;1H%g_X7a-#3_xZ^{9(HWuvbS{eyZf@7*QjmE#;ob>Xs;UjmquyeIpT*`RO7es$*1mvp9Qm5L#K@ZywLS64#vUQy zlvAD)^E47>t&h_)i~?>>w}j8){%=TK9YBZ%7=M}|rmb~Um zb6v|^&fk;_j&{iYtdi^L?%{VhZT52JiLJ_~V<^1eUo~ERA4!D>A~itcPs*1tc)tPX z6Tr3PnfcVmg-vyH%YL+bp!h?Z9a)}IysQb#H%i%neG?gk)vDO+3dHb%U~issj$Zjx zJge?Qpi3@rwUIFk>;ixWW82>X4I9v^%Fsh)SDT-Jx35-l&B4MnH+Y&bcextfc!Vg0 zw0(qGO7FzDTz_H!G5hajdA&EV8Js9ayv64H#pc8UT;PBZ&X>K=MQl;$V5!|A5U%MV zdLh~Ip)gM^N!COqeRtITNCc*%2ju5N-g}VQTd&S-B(SXoR+#dVl8C^l`ODtC3ovJ9 zx0vRbwdA&}PJ%iWbS~AfzStaWG0TX-&1h5oqXZanX6!J-oeUV6d;YgELhPTmgmfet_b>XW;V2+0kJLZP^H z6Gql`o5=ZVTWoz}cs)P`c&U$geZEfzgmHoMCJ+r#2Xb(bSqp%%0^?0q>%SsJzyaAW zr&^Yo#4L_{b{{)X#!hCZqzt^;69U^w#NuQiW=Sb``*jcOd389;L{ zvZU>v#D^sz(t*y2;&ed*o0F(zm3k`4KPN}8DhtpQ*=+XJ5v>{LS5HQ-+$?Kb2?vsbf> zVcBr{9uD&PfJCN2KvGQw<`|L|xVX3wW*(S%Lk1e!gX`8jki1{#DHUIS{*Qc9vjqj< z4``g|m!I!B$GZ97gtZj6g8b)h<-KaRt3tF2itC-#m{Q0gRpBN71!1PLN-X44?)3^I zS-L}XT5s%iO*ctQ+p5^Rspen~udUkZ^DL{Rq@_L6mmK-c1q6uB7b4?D);?H{DXG@g)3jl971c&iWRaY*us= zh@j4U$u2WH7v())8tM#hLMfaGiN^aNZK~f7t_7LCp`1A70w$m`diNB)D6`T*;17Dp z>A|eH0Us`BR2n!(LI`d#qTj$pk%5I}{diC~2RM!ZD^alEf$aK6kU?Rf@;4lMwy$vq zCUuw*uyp-(6vL?c)HaSKqs&Q)sJF3Cf2c%_R%=+|ma@=0CdcgZA~%I$PPC>mM+KBN zH>M2ym6U99HfU@#;PC2i0DT*g`fFXEry~%AdD0ohDFWKg|pAs@@?p4G$N2rk|K@NZS{Lphf4Ys6ryAL~VqSIGiklyliexB>w4-Cy-WkYU@kWFYLCao@OUtWsch-zTG{BSX72Ig=|C)u!BHQBS0TWJl_FLMeZfL< zxZk)IQDhgtug3eF?cBwbj zh5rpc6-DMM;2V(I-#6@8^|%-w^e+SU4z2&#`W35Y*xfNttNyM}QaoJNWtbJr_D{d( z9;{6tjk*D*mkAtu9i}M<`6M!gy!XLcd2gWnS4cc8fC5OrbNq|39_2vKnGBKT_gUMJ zedFxv{a$jU|4nVS3H=!p@;b%NCq48%bi^?L)pH!=OmF_;CAP@5aZRO}z8Nz8RGM3C zH8Bim%IRNlJ_D@ZRq%pFK*1I`K$ij|0Kfujg-pd3CyfI3~IqYWCbedVDP)a zh6w5RaeG8$WJ?2p!p~FMd;MRwi-jJj1WeniWa~{{3;hPlO0|o0@TA<0_FL(OlVpD1=jNNC{fxF|Ipk^pip--heU5rp8b=?djLo(V*s@y3b|Kw zLnJp?dqBvg>jL>pj2433LwuZSMEky8k49Zd;6 z5dcNaZy-f5h(KRopW*rQAHd8DESUh{*j2r02Dw*(H}_ix?hU|G;#*J<74Q&(tPX&u z4ZHh=HT25BDfJbwYi%u3V=@5l#*k$PU>pI5-EY9Cik3DzW#|I;H1lYy*=JX^;L!qk-#1Xhv2Rj_0VUxCd;` zA+k|Y)(-#Dq1rTz)?{R1$>~cL)7{l|mBgSLnd>hBOMC(V{Y;*!RBEt3N_p1C5&iuj zb-n*3cci6X7pHuyda2(>h3`Hg?N4WMbG|^}FM#($esbm&KtB^QvQOtjhap%D>EVh4 zg$=Hele^HsMRZ7%m)H5=8IZaM>G}{DJ4D9Db^s361{nIJ#y`LhD?z};w$7jNwMO!a3SJy+l>O%-aWyPva9gK7$Yg_?JMxyvuGsC-)3lkjj5l@K+O% z*bzleo*n>%Z1X*u9QzAVHxZ}Tuh9-YqO{(m*yIdi6i)UpD+4kfR0rwPt zqXaKu2HPf@tibL@$o}RHix#4BUt{I#4Q|{ldr&>945KJ-rM`K z7k-HSkdYr{jhf5vuTrL=5cbnQ%W2r}O35|0&};NpyoqL>@;>_MKsf(7IjG-o8ECl! z2Oc1BjJ2^>!EmZvA|oTS!u882hUxn1+1$v-BC^>NPg6-M5Be zuUCsoQZ7`TFk5Nx7T@A_tV8y{ZKEtb09+vt2OJ*nL zCKfb#{y<{5zRI7LM?!J*p86F&FPdT?lN@3CSo>aE!G1^xPZfjG{Kb>A(0gchqS?CLEgjmX7@&*GSyy|f&;KhsY_i$g1x6RKmSG8 zKLxO&qSpg@uhm9e?$OZyhZ=4-=NILj-&v$UOfLDEGN$=G#@@IHC4|-Sd(D8zg#mrD z$;bVB?D(`MZlcWOpXF?PB+5b1G#mNw)n@AB-hER;}qg>K*64$e*|WC zIWV#V73(lZ;oBRa+7Ca*F6~x+vh599Zs_kz9uMm+-lh>g;JfII)tpy%iq??IvQcj0 z$xFb5j655X406tG4URt2(wyc17r3E0HV#qbftoWVO}F5ajR70-Smy_oH9mhGrc-`{WD`FZJGmG)(6F_W^LL^Z-VW z&k-?xaa3tOX(9Xv6LPPzJ#lw8QjB>pC~RS{#(7iga)t#cJcDLlXA4(4*1_NZ5zA1n zyKzz#@|y8XoRK{JyPh$^7Y)%ZRDcG1$5v!(0V8iuOt(5PuUsh5h7iXykPb0|6l3+9 z0x~K=aKCyFDXNqxLZQf2sZLi@z}0)I5YA8-fln$?jhbjC>YeC-JYi#wM)QLH3Ey|< zv$-a=`jN7(OS9(WoMCWUuH$!{k(OVsFf6)tqa@j9b*;&I91^q2eBYnkAJmlE;#< z?0PTO`~U0m!U2Ic5BgYkNT5x_lgmSid-r*OfH_)w763u~s72wweHojdF*#z{K}wUR zVNY={b_(L6k`fN&Vg|Csmpz$!DuVRZNEXb4;wGS?dAqCYT7R`nDcy2_AJ(L3Uq|Z+u)I z%i=%ielz?brdwO#yQ|*!v^w)qcTT-;i+)x05V(4zXqIF=1&vUyKPH%E`6O( zCJb4Z6UmNR3%#2xdlnUmLv7aMQ)l_|{WXzy;Qw(o?fG@nCqvqE0nVxn!K$;Ku1o@& zyxqdGK8SodGapqz&G-beOd zy$sS8)23X&**OjBM({lopqo>ERPC*Oc!&Y7W)xp^Z{5l1zo>p%A7I-_D>J6)DixA# zrnWD+ud$Zs)DNWC=wsbQ35)kQzO^C#%oKUA-y?KO#bTCD?9>% zW5{O;*f}B81zB`tRUzNZ44xmRombnfo)XQTL{XqO{qA~XFF$eT()#kYjKLqI_8K#H z;kke8HelT#y6L1&HYdWo`!F+M)vx z$V4^<6;(w!^FN4Wpo95YEQYwdnmk>nj|Zo);TJQ{xnof%_E1Al{uD zfNdxDC zQLe|OTzAhVfMz8)gZCNY+3cZR@GJnj3&bQk$mzO|r$RK6J4}hdRT$9uN_VBf4-}*# ze|1FR-H5gKVe*vO(2WeO4wXhyh(pEJ=Hmr}8e| zQso=H{=+>mrStLAnnPZr6qVO6p_leFSu5-VvgCXdKE(N|l(W8LtdZ8TaegMM^6gq% zwY0O9CD($v-5J^Iir)fcj`@r4Su#~1$zL7Ma6!OdKOG+o;O?pj90q_I1-jWIV5cPq ziqxAc2UtTfi?3EmtcQosorn8pqHZ@c* z=&K=(Y#$aJw)G4)Dg1H*|Ly28UGCyhxd{h^{m&31443r{0uDwj!gH;3cYSM#Nr<*{ zm`!Ppt4xxL09!{egFz;Wj9(z!gQO8^cYUxo%T+Y!a%x*0f4p$_W7fi)UZC&EH~55T zz9FlB7Tq6{Y@6?Tg1%=YR}wms0qj+CjzKS>bf0oJ&tW=_ULzrtp8ay{op0r9_WgCP zDodsT&PBhiCx4m01~4GY>ecVbeS!iBe?4iw(e#t5hh4vrD5EqA{-H_WpOf~FSF03t zYn6Ps*IKlod+fC|V4-RyWT-uwwCx%1FmI^}aR$JA&=(3lY>r)?6;9_?Jqb3gCKb33 z6{ou#6l(VF!0;B+PCqQ-1SQle#&EtTxG3o^(S#&dO)6b5E_f2f{;_=4?54+hcJ_c* z-fE&zb8V-)8q;zKy_T_Q_0Q}9kG$2VK*dupAlVNGkOBc*_yaD?>ugUzAoQs3{I6aC{umZcCfX+-wDTtE=CGGMzL}OSTvvLup+TO zKBK1oSU!n3^YMVPyPm1Ho=LsFPGc);%jIsP>X)>ZR$)~>^<3I^PnNxk;BLii)C0r%Odyar$c5cHOL$D^ulikxKEmc^ep|{jk@~=A~(>n=1i%gA=paUTnQq z!dscQhXdHDu6KkBH4e|y>a>|D*!1b!gDUrrE$4Li5-P$UwSGFRAQB@YF?PvebVut= z{CFNsqR5aEy7B(U7Rgjc$nKm{wmk^_sVtmU*!dWx->71n!x=@Z`$_-8STt^i98!kDmXUM%?Xyx%t65weK3OLt7bJ_}wjG zi^ZEO&R}E5^G@mFEc@BYJ>Hf;zkWxltQ|EIeVi zJ3N-XpX)zSJ8jqH0G5g<3$Hl&XLj8#hf^@Ufx;J9)=;n#VrMJAG5f&Fc{lh+mY0l; zyrimYme!RY?X{64OXqNH8!rr0EvFCdsOo43rC2j0;8(^3eDTq-;$ghOa+gFy3te_1 zu2K&JyiX?9Kf?~Eo@>KAo{-nM@uk&R-Kun+o{-I1C>qYh6kpE>_Qfc{7W(~N94Dk3 ztE^w7HQ1Pjb#~tz>7yAOz=n5sjCnd5qVU-mmbZ-FQ@e&WPn!9SOfA5;LeiD{o@;)k zi?*7%IRZW2md5>5_;~nr>^1)E^bpyCjw{muviF?>>okQEO^=rOb~#bzJ zd%B)37Z+<~n+1evW}w+AYUO(!L_L3NGiIiytb-NhYrh>u9#&MGz+k@OcV{0rImI@2 z%%d%NFeB7Z`Bzstf|qDLF1^}>DjIKg%g)}~pX zv+OLxaI3#ekviuP*`y=n9TwM}qR>a!^LHxIslKJtL5y}%kfxJ8dSHG{p2H#4P~nix z?^DmNKtKHx8bS{`G9mnB8+5SBLvw<$Dy(V*+yi{xln9#chX}K=n2CU5Or|Q(S07VnPj;kRvzA`lvGgTcJAS zWe2?@0dsx6sX(()_Pku452i9fiq5cd;BkT3#x3Q+N#$I(~KUOjmABdx;#0|c;`Rx@tDA$ls+pb^lfw@^3 zWKY#odT@;pEV+iqlF{YlkVbPn@0~Xh9f%d&h|VmmzDHA2sn_cuU1241mN@*)bm6lk z-E*fWiS?{mi8Rx~L$2};Tw(@~=;808k-7$7Nb|gR?Y|@G`oY95k`yhQul4xshb5 z0P7%_38t+xD1`EIC(O?VnI>YAf>JJjKl#1!i!AtIJ>80P;^T;3E{>LqS`@L~a%d&^ zYIGG|a>CtqpJ)8?JyUqCiF@>{Wj+FK>6wBXR=QFkLF!b0n$Bcz!@162V!dJ3$*th- zwxt`}Op*I;CXlC=Ib^XS`MWA;AL$TdaZyOvfj`0e-s7&nI7W55 zNJ1(yn%cFUih=U@`S!Jo%b>}v&G-w;sNNzu&}r;aRVCGz9Ov>{eaU*YV(~5$-SoS{O)Q^@ySy;NA?(aQ!NQ$ zYhCzfoM~%zqm~f|5eRbuZ{|)AEkGc^Ml2?HuQwQ7c&QF9iIvwi zp+?lun{Ei$Iip@{3>?&&1SP0YSBG%oqLN#U;G2A}aHjEXTy#|IK8${h9bhS$2RD_P zRiot#eMfI`nNuW8%aLZW^_}X4^)(1cmn-HGSl!`pl%Jh1E>0D0k4A)qZZ0ni8tt<0 zV>3fzwJy2WlvAwLoKO-cJE-9ja?_8KS~YlvZ2hitm<+Q)psB-7&)-CcMM$EMO9%Rf z$J(Pw?YE>5i(O>2M3>TKuuzzlOsGV|zBif4MDtebGm- zR=$OSLT+eJg)eklclTo9gJ9AOjeC6Lfvy&Z=adS_XOds6;_sW}i|ptdra|LQ{c7`p zu?{976rUeDP+>Z?kQR={({`tkjvEpKZz-CFZ^gMYld+&c*-xe3ujWV%!HB18Ttd63syUq z3$?%*8m|bh40|sD_uNU`0nj?7FLodZ6Y=5*`Mi!m2!AEV(7x|g>8+|WKWNnC3}5Z> z$q#Dr+#6W&>9zCeXOPe&&{J|S8u}Oi*v$%ips+s%pHeH}UJwoDjF>}5t5gp7olVaJ ztALxkU*pDmz^-u=Gxv8bcwU2xv4Kw10fl%V^=CAtINvaT%fG-s7Ni~GKrij4xCxBp zWq$BdFdL$1{PZL}##04Mj0S2jbhTJQf9^IxcTsQpEv5b0Uq1DA z0HbWb*e4~gA&9A<)53v5p8Z2IJ|o=;WihAV)00bWm-s9qF^8p|D>z?fF!^MxknRxQ zP29g#^c}~$TjbS#BouPdOkV^nBqf=w8+9Cl`Qz%Qi_hrABrA<9bH4*QN9FEPP_F^- zT=BYYCbh3>uhBHoQGN@5*x`0JMgN!9OrO)AKEu_DMGvKN@oVM6;TWA_mHrmj==H&! z74eb;q#PDq)8>H8+mPm2GtloUquV~wXSt~)P%nI_H3132K?d={!VO;CV8$=)pOw0ZF`dtH`)kB1zTUpZ6t7FasIE4faxX}b zvP@}PLOH@SV1FyNemTm|J3QP*CpoCE7Yci_00xW%-GVCfq1@4&c-1V|pJe=&m|FM% zJ^KN88n1TlWu*tUQ-LiZX-RKB#6q)L_231sR9edcK5qPp`oZh|HlTWT#Q)0bHJnX& zRTbCc$B&K8&E?GW8MB<%2*?kv7?Cb#~k^&yA6>}E~snM1W; zf`w}1ABPlR>?$KGYg0e>US>2SSNGtqp)QOYbK)4YT49CC02jye_LG_JYR&vue`uma zFnyEI30LLr`ej?LOLRzLw0%F0hc;v9X|*;;;FBU!6)Cmtj4!{EjSi-nGZm0bq`CIL zA+;ChP7jD&)fRP2(#(q8m%h~* z&WR_}^l(qEms2*Itea$_*p;b$Fs%m+NdIy~P=Kpg{<=tFw)z!fT!2z(Z;`gw>a(BJIJVI6hFI8@kVjXBeZ4zjvPcp zmEwhHKC4W0;9h?hYUf(a(7;J1^eepSaevJCKbwYkGvAyq2>srlJ>gJ%KS9GiVwOh~ z&_L_jX>g9vRtXXvx3F6pv=qJ+Gq0=}+@B9fpnLDb99XQ#iq_MFIpPeIS1(Zw!F1Ol zo$V_lE<`j?oWZjOJ}y)MSN*=H;#~8drPM)pM&tK*!zgMw@|6af-l7NgSD$$El@V9 z9xLIktE_8znv3VU zMpTqnL(yq})HPS%*7?hGu3zeqr}mC8;0X1BoKFV}akuGUqg|El?-LJJcuvfP#r7~d zu7Fat#h*d!5sEn1S8!;eg+`tb?vw;VSMHw=@5XV%`JY+k}8<`jHux+|26J zriJZVtK2*83$ME}|LU;R_0q6DgYHk464P>OVMo2*Nj#fYE2!+TG8eB~vOpC5#92#Z zi}Zxu?{Qlz64;WgSgIPnt00=@Zfos)&JhQrw2-VMlTf)qu z+dwFF=2{*I-zoL;OA$NoP-VS{Jcco!rl55xJP`7=je2|&Oj@DkB<{TzZjB$MFZ>87$7$if=y5>9gti;03rxy!O z(YC$R(D=L#I|za&=EXH%3t|VSLsSJ$ZTCr=S__%{DRUV}b~N}xf4mtnkKTjP`)VqL zhf4k^YG}><6-aJe;cz2iM1D)%0NY%`D20}2sY*WJbjExpB&6} zjcUAycHf0G4>HN2QjN#-Kv+9Z@A{AyOrot|$&1S`)w$cotLX{7gmH|V?6@QRxzPu@ z-_oa-!7ZmdwX6j3_ZtTka{S!vo7^oOkztOCDNLDv+fLN_2DT-&e{@DHb+I%-VAIP6 z2Bqb#x73|x`!!wSg|Jhs?I;3hQeW2MvMhTXJ6ClZ=nd`Hm`YPM+AaQ%>P+eA7h5C2 z(HY#HXqU#9Y-o@E^gR6xh7*|6+2Swjd5Ya)d8DH&tVbBAqhh|i%WdYovCVCFTqX^L zF=lk~J6j_nZiR52%zk_ERv7HJ#+Xxu^u=qX*O+DXhn)6QGMC{q-DfK^AYP5CXb8AF zcMsI4v`FE+J8|FX^9QpuucHB+UE*4t!GqasjeN;cnzr$n+=_HH-Dq;B0ly z_rONGMQTLUHGB@eSU1-g2L2Y49qby8BX`w7Kr?zD|2D$;;sCFMxqf5?hmt*C7t?gV z`1>dP>4Iw-cjU!q%=L7v;mHCnky)~FY-WF6fF$a&SGzuP)aaLfvFdwpcq#!ZD6GIO zfunU9A)ev3CeL>*Qfz!bbUmx?m8OYpihCPMA(Wf?I9`w{u4d^heUe{4He@SslI9)o|! z^~>+eE0=E5G65H86zs=kSj$l4k0W+#LC>=NIK^^C6`%>P)&yTX&3}uO`jx_N*w7QB zf3?a@QZ#_^HJo$?Ad;}zuDphm3?^(2rw}tXHI?E0Ojy^<;#m{Ilw^8&#BI5jtwEP< zR|h`=CXbHrhmMD!qWpSzFpPI}ysF+y#00iTuQA_@!}w&tz@Uvw8hv6@!2-`SG+*WI${Ckj^uW@3BEK7s^_)EZUl#6Hm($^=4 z&#c)61kvj~ib?q$zi;yaZh*WAv!CUG9SV7@&kw%41KTI{3Y^DQPBF6gksr)z)z=`3 zEIw8q{{;fbBW;}k41LfJnm8>Q#t)s**mS?OaCEGh!MeSap>=FzS`-WL6nWT1^Y9Ct zfq?LIcz7AB}z@OGV3o0F8?_pD)~7-8y&8XS?!BzuZ%{2f&1;dj>&N|#6tV0R=6R~ zU5B&5YyumT8tjbA=9`s6CYsIi^ygTnTY(Ae@4PwA5@MjzQNwk27ReaN%m3+zfy2;* z6=I$rhVMJ3F4<37&P(k*g=N?5P91|&gvA`RI(K8kXNYk`BJnW%r%Lsa0NcZOf-A1K zy(flo3P2CB%>F_=oYmeqy9JN)gvNFKFu@L|rt7(%RbC~h)K2cUj~i$4fv9;()gUXD zuR}ZZ)+RwmmAthz#9`(2hc$DfwiV$cE{v{`7(ZT&cD(W0;5mKWkMnX?_iKA4+$U~@ zm4nL+uEDO$UkMZ)asp!1$<3SkRJ?iQpq2`ai`&exzCfAgFVD+kkz^nkA0KyA>>UoI zti*G)Oz&ooz$ImW6_uDJvt`)-%jI|{RkVrr0kt$bI{HT40MLeJnGpg2SYV9+_dAwJ z!})B=h=GY|_k-}!$*3Z`)84G*0^m53LsM9*cxHNf-eh_AZTFhUO;3*m%sDt!oU}zPKV2>hIivt&;G0Mc3M`^Zl?4-K{)R{g>ZDlCgi)?-Cb0#rn91 zV!Zj#=pKU6HPf0PRe^qin-jNz>H&3#W$h|HTI=g8=d?lpL8sHxA?_E6*7A)gHJZ$` zmes3PsolY{_W$llxw7zd;TunT$j(wNRu}eONSN`2&g?ph|MON+U`txeA3{G!HZ87E zvkzm&El~})aj{aN>+jL1 z-qYob_4U*=ZgEl?J*)W^z~vMC%b-RxwMaG~S&2L6^r^#s2F6XQwGGicQCiEYEq@Vs zuhY}Pp}qM*1_!$j#WeW|uTv1hsnLnp5UOY7wY268X12Gs2w&=nf4F1H!js9XXj;$G z85Lw6w)yu=l&|G&<8cQz1}DPht=4LEXdm$P^3mUl4Nat(PLm5Mf^A_s9nC1upls>xgqXYP)UPGHbpy=Z5k<0x2yyR}xKJ*vXqyg|!a)_wE> zk?l>7I%hdsk)kV;`%|V8>{TM^XCEXVFb7QZNITfQD^Bsi#1KTK!XJ8R&Z*7(r&}8O zWfm_#$Mf;~pC`CK$s3J+SE`YieYh0FVheCs4i*|U))c7tFa92Ok|X_QMFaj3oxt{D zwh~zog#0HU_JR=ak3qTwXy_~Jy|^*;qeR1(1H_yp=Ew(%)$+On*0rb+2_hVAR*H>^ zBAAB>rKp5kQHcpCL=Q|`G={9%+p7c6n0i4;llJq8>Y4(pEx7)J2NzC;0{NjNLeF~M zJnVy)$FEH6HlCIKlP8SLoFKKnf$0t7{4klBo7=U=aAIbQxPs%^lmX0N0&2=L>_tHblMT;{)M~W=v#+hgweUGUEV|tqw?-78VwGczEG)aZ-R( z$0FRn8ohM~cE06ymz{BpykmqbX_iSX{i7ZBT0!b6DiS6pd74eG?Wg&B=H!E9lQRB+ z2jGq3+4>SdXYPGC|KM?K5-K_0zI>$g!JRnew##7RhA+=DbhGjdx2D{2apZB=(X6P3 z(NHP$`-x{CE~pWN;0Ed0Y~$X1-p)4zH>ccEC({Xq)?13Kw%Cn%N`X3}GFC!q-8vhILk@j|1jVEfef(bD;Xm$0JHB{d|ezdo3@uCZ{14>Dl} zaJc}~tJ8enP0AZSD!#i5TNC0QG-uQ4vuTwVM0KbcyFNFv{C>lBRi4t_{jaJ-A zhq+8eH4bYUqGJkLwtId=y|2$%HLf#li>YO=`a9b|cv%|hb0CduPTRuDW{VF_B)i&? zQS#U|77y%vWGsJkuPz%W$})Rn{~(W&Eg=zMZk8#a`f*%15%y;EzDs*{7HgrL`fwO) zFnLzNpN#()_<4fbnGHsQV$ojc62GG%?k7+KZev?Q)zJC~TMCu6HfMQ=-vz z2@I{c{5JfBz8~dq#p2`l;=A1#bZl;oP>b->iTX27m#=KeQ)1%L`N^Bp6B||%gE`rH z-ggTFUb9*XQyY}L9_C8iUKLSkJ6=&AdD>JB3qPtkepxm%G?=a2sKjUp0lP$J4i;QC ze6~#M8qNHn)-%)@+v5!T4XfoJ;jce3KYB!S1Ld-;hKaHd!(Xk$I@I2sF;!Gm_8PoI zsbb99$ej}Tv)R5A>sGCM5fRvvm_9ei2x8{nYpFq9AW42-Z9fL?6ZWdEsZwAo zzmx36soV``ANm;(ocsh2h%3_GeoW5HV$l8*xyrwYZ(!45`&iqqawvVjrSM6_YNPLa z*bNlTvN9&v#?&kRVjP5eC$}3L&ylU4)SVg>=P4)YFY5OxRdkc@+7yg}4$il6=Paw@g`^K5PRy9=JFozKCC z;dZEHp3TX8wb-WGlpH6t?ooR?S2XI#FImB{+q0}>8x~8(WgOCp(Z)T{)5wzcjn_+- zrcZBR3-!hNX94aXG&G9&Zbym6G<-=cBOtew<>l*p0r zR6QYymCj6rLWMD{QiUqx0zG!Eq8DYwgd&>Y>S(ta0fIQT@!6!IZCSffoDMYEMRWBkm#I z9eh!$*xs*pi)v-a4fo68qmB<5vc#no%Wigdddl5(>2^GOS;@?Dk-K0#!BC|H-$nN= z_cy|~LV{O_v}mN`79q*nAfvj@m^B+S#>j6U)|JKoRTq(7ED4%OJ}<8WIcasxe{<;n z5%v~fL2X+bu85>47$6{xf`}j~9g>QafFdnj(w!o$v~)|CfOLa^5+dCt(%r4Z9Sc4C zoOA#GzxR2z``O#=UaU3OTw{(ozIS|cqCPh~cu`qIMdfpkmJ}`W)atv+&#x())7#S~ z7n)YTs&}xPj#n?MT__1`%n!ENyF_SrQ}PAsO9#zQp+?B`a`mREYKM8+mYCE!kXaSe zO11NcLm+U6@m@M#`SQhlT}^T9NYl9q74`rw>WjK4@vSEpC#j7VoOS20$Kor2+?4(Z zFEeXLnQ25ww->!S@7^~FQ|hh(Lqp1B`DI%vr}lmkpW2&c4?I@@-54hwoq(Sm*RS3t zo6+T7RnLQEX}V+qw>lc9US`~Hy!2(cV1wBef5ekrEwQdj`!{63{!e!GGnF)K%HU?J z1_Xr9(yPI2X^*!T@HBZ|AAN5wNI!SFuRX|oSDrv7*3i#-qsqlBh2A6oyYl0L`#upJ z1jwu>6}$O6rgYM3R`$V6Dcnmul1C7(-eo_lVMD|O}}YS8+L;VCjDUHV6qq~ z=`WrSH$oPbzIdU{_ZVaCc^S#p=Xw(Pa4a{G-H5Z}_yHsEye2)c2EAFsYqRXyUDZeF zUy0QY`;nZ2u|F|M(KJ$>bt2Iy;Ny3xs8Du_%SaXfB&G7p zXfGD!wx64^#YsE(K7@ANu?Ru7YzTAvJWD703!`SLu!81*%IKI!mY$nCRQ|F=g+IsQ z6yquUBpUovJmi#kO~mM&ZDLzKj>3T+x}M(mL2wazLFL!wgy1(g>7om(@mEgPzK+Kk zT;50|uL_K&#&+c0`v#SGvU^}HE{x(@cq$bp=WO)dxe1pj+WODL|F{z)&?BNd?Z`4- z;lF?HL#nw!&>tYlmcda<(FU+FbK}NV>+we_v2}xf?C}clwY*;|*|>sPd+|qB=0~(h zzTB#e{Y5jIC&u|D#j;(6m!x00y(JgBS;mq^%vA$1Sm~H(q}O(lefxNEiCxL_2ag;d zhUJJ56I@71(2mkM?iJS7(30VI5{q39T=<>ClL+%*Sg}yioOK7Vivu6!-{|5hfD1+M z#t4kS&7wm!0krAIA9AU)V$SC26UBU}*^!xWDkX@zSi=N9`x4K((*L>&}GMTQ@aoD0`s0hG`gosIH z6!&#D=Sxb!3O0Fz$O7K5DjB~>XP8`O%4_#fvmRz6{9*0LVZPgxo&jgy(3*&*Zrm^_ z?}+fz+TBRCIK$>L{9vFFT!LBGwN z$1wJ}yX!$AEA|}*^|#_}k1F-Xk%baAUzrx(mtE)=gf|^bFR1dl!g{@1hGcQm7V#KK z+B}prQ|)m<1MLMp#){4ZDfb(*0+!*m9yVSB&u>d^1p}FR3D~9$8;?-VPs|a^AgIyI%%JpddfoWs=$iSy% z*T^cn)`+k|2*88<4EI3Y1f)0qO6^I5bVrHJ#zAww{>Y~zPwn@^wzJD`Y%zkGqy+?q zPti@=zh;Pa>aPS}iCmRQ6O+z|kUUO0NMQOQ+Yps2L8z%>US5^+i)DKyvMTPT>s^^< zi~se2cf`Os53RVQM5Czc>)F_<*{IIDE*zY5E|QHNRI@3|N%-OPX^;3E`~CXGb|y$J zQ_L1OT~Y@DHGbY4MQWGpB(>(=|L6OOzw^<*YNvdl15@KPU#;)A@X>mIZ`6Z(8f!l_ zEyuhzCM_xsx4zG2zC4HllJ_l=hc{T5Ol}u!ggpH+mW+QedcG!G30Vj@a@hR{Gqfff z*}d=W3;9k|J$B5Up9XD8eC}0CCI94jp5q9Al;b70m>ZKjqXzNXeTm-}4r0p#hfnYC=Rx ziT84rkuw~rOf^T4|0TDzjE(im^mWp1ze(X<#=Jv3zJ)OiQXWQcT&XqN@L)Of88pr! zG?Nk9ZZU>J2!5D8As1amM@p_(o9?mT)PEAg$gN*EJ+M0M#R2eRGIC{gjn-KGSBkk`h@RLq| zAFTw%LQgsLr7rTHD^Aw_$9K4>XH6A_d=nl+0+})9H~OtSUC>utokzr2KkS`Tp1#)O zj%V7lWOI=@xTRaMq3a>5o13%IZLMuBY`LN`qw-)C9cmP@QXXMW+An1mJbPD1dJ<$m zT9ZF(Ld5qdUki8XV?G7zTeaVBy5$Vsf0VD5ltRpHm%{R75htMe1`lV}KB0e2dKijN zf|u2L<4zsrd#>E({Rs6U*SH;Jqh_^bbtsjTP1?AfoR9=ZbYKS6+C~ioVg`-#2W)z6 zDLS(TXbN=34Fz_tPO@s>c)z>}QLK4;IiSyb;`ZpXFCy#bRbg!mo8$MJ8})b>DB`7$ ziu_;vHoo^R_taYpjj#bG>HLjid8SQ=O|hGKjgd+;&9?KAFF$1`$|5Ni#pNDyu*kmd zKfaosM%|#Dlg?y!3 zO8fVw63>pO<3}`yM8Z*O#W=531lJtY02E$0NztKRJ|bAMOKPvgH5uBCK*Ei(S>Vl&H3N_%BfNV^xG&Z1 zfH!!?iK7pV#XZSgw8*Z#I|DKMZHl+1UCe@~H#ftT=v&%bkb2=D3HKA5-sS7|J}h8T zZ5nyh{^ff(08+9vdIbDm`ooe^_D<8AA(g|^o5`s7^pP2FYI5GLhYZM~&97%%X+N5Z zgVyQI89kjXWG2>V)mM}&12p>ZjU6XIq^-i}p?Cwvi+vODTyG`!c|kV{bMKH?_!!7H zO>G=F&T7e2)o(n!Rw3VMynent%w|O>ws1(LP@uVuSswaRf zsJ*Sh=g~(xYj3^)Gr5JE^(#}lUPL#%E z$^);EdVz$`v5c@VJLojs-Vwum)RZCuw^2lH<-$`Lcdk$9+bJbfGUz?_v-jmw#WbinP)(X=ME{vjEeSypTx|#v&thE|RCmtA zr%R8|?SaCY?QKt}zu|?1c?)=oStrQ7!K+xQC{zyS9Y+7QRE|ow3 zqSyAFGc~A|kGJEfQrBU;yd=w@wjlYcy;+(i>&-og9kOEA_fCmrMjuA)QjEwd(NcRZ zAYa5xm=B5?XDuD!WcQ`ti@pmAV^)0H7mMCIehM0{eRG7D_DhzhF2^D9ycq$Am(r!p z##wrA_cE3#C8V>71hwbs0=*#O8qhJSM*O1du6;9NtXYE|X(m84a@{#^i>&!czRe}K zKvKLBnP4uRL%lDhX&WaVX@g-`yj<$M(~mFEjy;iXUGbbw9hAFCTchWK(2S1a38+)& zq+RhewVA#PR6F{1WY*V>@drFTw8RRD{?+jyfvY6mS%x5y%n4P=G#^o`AJhbDPwux` zUDB<#a~;gJ742l}e5_iFN*H31xxqF==|K}ldA-ls|g`^fs_bG34=0KjBzDlzj@6T9|!)%{-8c4NMwBi*^Sc{t$rJncJ%Fu7GxFR z+n_mIldR=+5^Z27{}=elZkwQGwk`I~C5138{Hel=IP5Th)=_p0FU{5ZDLFt6@jYo>?vi{a#_!X}jpc{ml=C@_pQZ#r;I`-6`Sd6_~D^X}3 z0)idEQ-NT=Mux7izODmP9BY~TbbfEqpW$1G&z%Vswq#);J;u9D z+xIbPTj!p$PN3fN$*UvEqoE1CFIP)Gxkd#ST+BBnR#&8pFHTQ`7rQ^NE)P)J&2E+q z8z2mUTX&-8yLyqF!KZu96(!eRZ}2v44{{p{sarp!*P$8Vs^FJrOULmaT^I@Y@2*9Q z2Vx^pn}^h3D&zM=>QH1GkO|Z)xCjekyujP~BRwEYCs6Zw_f<9r#_X(MSKr{;oB77v z{AJ*7;V*~nzW#8b>+1&PRXN8CCHptJ4g_*17kI2U9G&tMSgO6{I58 z9^~V!LEUIdNU9-?5p&R5%R#p}yOkDQfHqH60Np5&oYkVvwtpCsl9EB$7b8?bunYP#Tw+J z$4H$Mi~J_Lb=*s{Z5j!dW|kZSEJmr5%US?o+}*6y`)Sn~zM)A4w1!vLh&aR5dzR>mW!>;&wQ;ijK`#*yt1QcLZ;Q`1?(2^RoI8fI8{!iEA7t zhc|>hN!(IF)Xp({c2QxtsK!;rKa8x_Z=@iSse9xE{At7&3Lj+1yoVICim`?x!7Sfapr4JA8%#69u#p)oPP>YnA zCqxG_zzU+}${NvlE`TbAUQlF0`q9Od_ME`4FT7%NKtx(KOnmO#tNXg~@q8_(b~HdE zeRd?;8ryo_x>7I2CK(VVyl4MP&pwQM(|m%-zIB`o5pY`#B?u(xS4_u;(=X$3YQ6GZ z{7s)EW;c|HaOCtyxerFHc)GgI-m?&rDT+9u3h)3&!WtQ}2$+jlgO3fRi-0Cz7(HR` zKc8cg`z0O*)5gUB#QSqBnDK_IFX1~hHzda22bH&Ja}OO+ zR;ddw9ya)=!9B`OJZ(FPup>-h4ahOi!%6MDo9^RjD%EiZh=nPdIgA$ zhmR)w+EhFS*)bBGBA^SXdMGA{LB|~3k|5>qtSv;o`!Y~Wc$w5phx}Vxw6I&E{6cXX z<;$BeIm6cxo^tQ3Rw>EU>TZ-hNtsGmCW=^QJ+@<9S#STBwo~~#8_Kv@Dkh^2uCJF| z#OAMWA1;#oS1&JAWN#kP|fJjDD_X6UGIN!pd07YrD5Lu4Sz8; z$ZzO%KKfOIVUkaWdVc)_6)mPE-!Rd%R;1Q#9%sD0n0K~<{nxrI$Rz6Cna-##?|h`%D@gBC%=^0|d2rK}mMF&< z15T}evw6?8m}s}h;XK%0$=V0qx3fljZrbLtI!7-FU+dcz#&=`dM6pj9?MzwHx>$_N z9gLY9@w5X99N=txcpybMdQ^xQ&7;^zy6CI z$tVW~#NaIBfPer)la=0FWC~-LGT4^oOcDUS{}+&S_pFno;m*r&`P&m^qn44K{jR4+ z4wS+0o}J9nW8ON>Pa(`)qRy{GxP<*A-k<1lBN(ATIPtD%`;t35iNW}{jgOCU6pQZM zyH|W&5M3o7I%rmIzglUYzk9opogwQl8)@b!MTBR6lPZHkAM38RKP)uzK{|oU_iNIr z9%j0p=O#|t$uV%yet&Y*I?(XV;y8U!?&v5h@Fr%>K_0SGjf1)1yvqL4{%wG&h+Uo*g$wgbr8 z{&TkVp}e-d)WOOODwND$%+?Q5!l9$fOtL32hZb6_t^zjMF1T{G2BCj~`c3WL*kxxj z4uR@c_@4;&@e|?^Q#aR z9C-ohM3LWj?D@7Q-vbIfdStJE&pvYXf(O??(?n!h~x5C|-;o1EY42XbL+ znF3o&=go4a}~3t9P~(~LE^3a6cC1PR{Qzn_NVJV$bMF&Y=$EjWk$rx4c4+-qx0!g(-7<|QsK%H z2cJY5eAo*%3SvK5L`m-N+KO3&$lC9uE%e!4VGaylOz;`xJ6jp$o*KNqn7j+i3&=PA z*d;*v-?5#ec7l$Et3sIaKVP48bnprC1lz03 zMgV9nY8`OmI?#8q=p4Hf;Twsro=`3TSx;yLT_ku^ba15tZ7Gxi{xXjvNl4zghb$v# zaZU9k>dpB%ObTE+#bK|^KU%hJn)$9%h_nj$1RdIsha#g4FD(|~qSj)VWwT$`w zePK-zsiOu$GTQ`aV`H1=PRqBSKKtKOI7f~DLbuE%FE1pS?qS)4ll@@PXZ>I$+sfYe5+0;*$3nkM5}>@4Nc=u-=|&eY)_|e< zdNS90^s8%B5?0pYyp0eZpT`b^kcC{iNWOlJIWTll-FJ}h2V6@Xwx}rGdhlV&kp>i0 zsU<;IpI!kn1AN0CpIf92d~kroO9@Noqm6`Ry6><)&j}qwJ>`7YDP5xkR3W6978O>} zQFebSMKGJ1p_70D_*}ZQhJuZxGQkrGwxF|nC5CUrFwg$rP9ZY9-Sh|_*fr*|KYkq_ z-vX>mQdjwm0i=C|G+C~OZfFi;osvP2fmri-;NBDC@q?7SVTHSpDRpg3R|3L$vY;1Fft~@6~h9cm0Avh=lzgGkhJ#JFwb~Szx4y1qk)BsXH#F zzQ>!FH2o9C4udBa!}>3VjZ zH~YEm`IL*kix=sByZeG%WqYz?%6#DN#vG8Bl%9`xDlQJ(Mts_1*o_^>PLJ1LC;E^% z`eKkf5zQ^aYF>>ZIi*Owf}2L{kT3mj#=V{Vi(qUN!FefU~qG@Gl4va#Omb_PpRgt{NP1=^4Ejh&NL z*P`TP&t3kDaa~xJ{hjc}|J9C?29@K+i;>^o;Yzyx@e_lLec$Myw%yT@m?WK}@_LcI zOl2T)&l{j6uSQMVm7#j@7al2TpS3KooRugw8I9<1;@=z6cHXa=s4;S?72o_yXBtR0 z6uae&;TI~#qq58D-@g^L*qL6L{SEod@02B&tMmQX(=3jAwxU-CRR+$lz6CZj1Q$4+ zv@X0UCCSdoSxpE_sZe{$B2Gfvcx|#}7|U9OB~6cpWtSk``qc;dwi#bL=5CMXbE&3u z!7*uK|9|LQ*RJF2w{Y-&zKVH)kW~){zHkzbaclXq^}~gfphDB}%Dh3~dHhLvB2Ev6 zc$)$x*F7r2vIwO)|)HLv_*!&Xjy zW($=5@Mq=Yrs91JXNmDJvD&W@CY+^R;Xbd+%*^YKO*);)(c^&#@!-;L{1T7lhxj&I z@T|Isx0CfCE@?(zyJ3wt_QPfsLSy)O7@A0 zaw46!oL99~%ei*;6L(@X7d-v#-ey}7Cb5hWQCAtwrdD!g5AIwp{=9rA<(hzBixs{* z>KV|p#;zz%+Q)yXRw(K>z5Fd8z2X_KP5x1z4&bMSaV9zq#Vp`-6qXj+=i}K!`yLStnu#aQnP%1np z*5_M7sMYdepD+GMP_(te%p=9F|3oY#304j$b+9AxGzdyDGe@Py!d6k?$k8_T(Z|{_SHKQ1v<-WcNt*a5O;9k%CG&k z^z34<=&w~1p2jx)oO0I|`?ctDx4lwZ*yR{V&~=FITh(r3hHlNV(&*FV=H?>EMOe=w zTj`ssw~~WYym?nFW5)fvQBDTCeFfL$+(*jZt#Y)do7=9qQ zxZG6T!(YJGg@xla8#ytvB4ZT`q(Q$q$#XRonqGN3(v0$@xe5kp*!Fu~xr?C&1#>a^ z_)SQ;;g=c{*0y1@|Zzqn6uXRrd?wQ{?W+`W# zEhMbCK%X@|bM<3iVAVj)+-8fYNDXDb6@^r9-mu9JIhS>vW>CG6eR_~rkT$Q%Hrck1 zw2p2!+gM(k*=sw^F=+dP#fBTa5>CTM!{yW_wPCX`BO<15<9~*dIXX&Z^bWntBW~Hd z*OYq+Rr#0N_^;wYe~OA%qVm{Vib)k)3qded^2%z`M*>6Tx7lU_Md**QV`z((w`xzG zm(`xs4vd$cAd$1@kdu3EB7q+8FEDrV)LvSybMWV`w&aN*3k z617uDs$o%j#-aRA>@3rW?<@U$c7^7G4*!Eq^kTBWx}9aOx}Ti?BFs@!lIhD})$*y$s9R%cAfra_!Uq>r38I6FXkJCe zokoNg7*&_gEs;IG)cGn*M@~X)Y}&PD{wX?L8Ll%3#7N=C|5>^+mxX- zEUpA-4ndp87Vu+YtFQ_sDm%TvRnqxEKj0SAX7A5Es8Lgj5TDUmU;*Lba^=_WU3OlL zs`xGU0%yw+sxd~zvSzhI$4`tOU>atmAG>s1z=fx$F1$7M~d()DbGi~Qt4 z{=EUoPZ}^W+myD{){~Mb?C`&ZQ(yGBwjwVvDWE25x@tygM)Libs=T_8X-Ma_-Dtbf z%nmYb1A!7V1<2ypll=byitTrj&mNAf-XnS7rRybcUZq;-##rx~1~vdtaJWWYl+n}E zvn}+KUW2Cu)@G%3c0MxxnAW{}^|_als=oG)2iQ4|=PBhco(#ELjRltxx06<_WdDV~ zih7K*XE9+s1Wzs$SKua9)Tl)oKgy3@FOy68d%?6{tbHH_9#RoS_|f_J{r z--sWlUw}G>k6_OEiWFlNY@$qCiSRHizaf;6oSI-+&g`w%xucEAlk$fP2M&q>i>5~} z)de%crp%YC*p`~3BFK5REf(iXx6aV44x@ZJ#P8;&>Z(q~jp+f2%3P&0I?s5(*pa6= zU)<32=-w@jwl(f;#FU4>-x+i7hyhwQ8>IvP384v}h_|bL3z~a5kLQKAJi`F9?DZQ$ln8TAFd$3X}c{2X$i?H&s-yHgVkBm86KVn z35!e{`gwPs=%@A)7N%n3V6SCzwSOhaK1O?vqZy>NcHU=ENPC5mw*YVj8mx?X2%p6)pgojf3y+gX_@p zfheu4DZyM?Y{gWOQE6LKjC}=^x?3?EUj9nB;JPD(={HlA4u)dV*8x`>ub)1i(|(mX z(fR%gD@=S4LR(0A8CO_2y9&egj&HGILlNS3bYo%N@ zri%x)5e9WT%2SC+H)X z-|=d%B*+QifxFN(RZ_zEK@Vp0lizSiZZ@B58NCMb(~(+g!T_oc`RhP~6KnTrfy>H{ zH&(DIf8kbKe7=r&1-!Ap@v*Fv?57N^t%Y{C$XZO{hh)|tK8qC=%H;hkIWM%A^Sz_SQ4gk(O#0*6j1vipTIaOs8 zK43#K_Q_t=c>g%Rn%~?Y{=>u|&kxxA{M`>p*n0wK!r!{|TnXB3HVf$&OZoy~l>gE# zImiyjuKw!am-M3FhrOHe_inQLv1_-@2t2>$&BEEWb$OSxU;|V#ci2kurU_k0j+MRp zs8pZMR51yDr`CYAI3GiC0MS0TidVc`Wa_)NfLQXxOSYTA@qJV!r4J4=*Q#Fd8$Bos zVkr4DSwUDbSm5ngNme0>VTbC}E-K8T)jQmv$$v)HJCzdmQ$F)q=qLYp$ds~V7vge+ zMrg}7;x7Ze#X`Ppi04=C1NcPVbpwa1&wmwqxXTRTihv9}W>&ydoP$R4=OVE!nz5d^ z7Zt`Y51q1wBv(*O3S(0CNOZXQ77q{Dhm{duF4Wq2^*ji=V4Gyoo2hvWdpkkCe4oU< z=xchOK{7%gk?%4Ms1G<^27AyeLZPXz0#_Cz;mzdsBB3h}ztqWdT2H*iTOdirSt9iN z58fIM0)DY}z5a!Y@xXAWC=H!E9>?vmaAB6BjpyDvflspe`AlR0X_C%XVwq<2#1+L% zu_9wMQ&%=VbKz^ZmMp$Ymc;!grT4_RW6}u{`%j)MoG{<93R9&_lxA7&kQwR0G21+^AYHqQ>@!gP|z~*S;C& zZbyUHsDC@1uU20go!rsT+__pzXLt4i^4|iANR;j?+-0?^Bd&2%M1g99Pu7sG;!Q)W zcx}^7%XiRR-ph?8R)!+>r=Q%kA9Ho|w)2Y*(q=Tv$i;FELcmNSiZ+Th0^(DF>;c4Bs!ZTDftcew0}%DMZ{Q-baRJBgmL{G~P@>G`IqvwnV@ zH2Isjq67|ry>5Z%QS*iM43qwu{_U*1n`A5BAwe!jlQ z+xV30iGj&Q&XYH4wu6%K_NYduIMdG?JaJK48Yj^g8Yklrnm!etyP#@t=AmZ|HEcqw z$kDCA+M}g>`A$1ACGJxe2eWZspP&{8fMneQC7T6ATGwL!%-5t4v?zfn=IDL$Ob~YU zwI->xIcFG!{q9c#RVZ6D4GUNE!83zv1J>=$uT%@y1!SFa%e2w8^V78d4D#-uv2|yqZ{W}70T2$QVU313&m~l80 zk4$*_Ux8I4QY~7pc`yZeM8)Zt1Ioj+hnSQkLa;b6O3ezcQ-tNiz5o7F{0 zo$yT>e7a~p7CLc5SjeM55m6=JUyET1iWPr^7;jz4j`{JK+z=6;giF9Q3(PVRZx#?% zyMwDh$%JfaX(-41h`ku;Zg?GgruKDT!lLkqlY1vXI?*~hf7x=-^Kgt;D+X5b>dY%i zmGu9%I#VmThPY*5Ctf(EX(2?d@PjYf*DI*5VRP3Yl;8b#XwUfJ>{8ZgUxh@nFR?dLi!GX97UhL&}~B4KjoEBDQ(Y>FS- zB?qXOB5H)tEebH;0@RYU+G-7tJk}nS<5D7MizMqy8fSC3xet;}-pGQlDZ-+7bECeA|4E7g>_PvCcO}hSF?h9z!&}ioh)( znGaMpIy+CDhmGSI%alh27BW3Y)*^PvhSAU^1XI9&!=i8)i)fm1o&bxS2A*?A*Ll9I zex|Cs>BpH;Ds<~H@JY#GQ)${fL(gAFIngk_OacY-DfRd6t}4$B`R9f2oY&7xSSpPg z!%I*Dki14NNgK~T7BgjI4v{52<*=V^UyU0PXLlPn{>giH+;4vzR0-(!TbmKaaL3w<xzlK>86DLhvuEXu3hP- zE^4f5C0_{QLZu>{m`zOL!J<@>?>$$Z#;)?hoeO2|c2qhOovS z^mDOHazHiRVy9WjfB1Ywz3DQpIRw}Ra(4cvHT7-#8LH$T!GKey8%EUD@6PmWY`z5} z=l4(Jww!2r{@vNmSY5l(PDyIxN0mJIJWC=P|l4JXZha>4e8fJS3Y zsF~J}uD69RzX6`|F+(0#mLHyo=qnONwI;QDZ%+yjI7dBAq6RLoHY?aAJBOrz7iW^EQ0kit!6;3#@8*MQn=$5%5q|NWmbKjQr#Hb@K2(D(EsJ$Zw4n7h zMutd|&a3d@$tE@84WZW>2G;;!0x;tNUz`)UNt1q;Sc|(AH2vLy$Ux!EV!yUvixfJ| z(#KkMg+Vi}U~`5(Z5j^YH6u+iju=c4j>&7URKK$a6M0(uM~tW8FkpY-?ucnb1`wL;=3h z*lgXR4rvmM4AAnnAKI&NO%8Vd#H|=G<2nbH)vwwi$Kyoo3BjOo>;1DCSVYop2Ecx9 zdQuxJCgN-fwITET>GU%eWtap0YZ4A00smk2J__Oc2z_t4?N~t!T=SlGcKk;5&Bq^E zx$MB7Qc7A3*$!4`c0XdOBr1Cj2?iy&953;nt6%*Yi#5FcXZ4s6bh$n9u`}rs{aIHT zW!@El8KRPKTs5{C!!I=-?(~U-Rxie@w(} zblTe`>-FHbYjKk9*;9UDzXg~`Pk4Qic-_)a-|6ytjj4@?S z>mJ-7*r{FzQy}n9zN#?KkLh|Yx`=Yw5efIuL2yh=yr10eif7USx%4gA3gbRHx2O-! z*`WYDcq37`lN=jx;jB zhL@kJ?%57?CCkD1WUc~7;!KgenWpLH3*=EK`5r+xB+wJ!R{a&Aj4hJ}|D_>RQXWbx zMjf#7VM_A9W3(RHRZMQuG2bnrcP6*vxjb?$TA;OV{8=VmS}6Y4{V4#vlb(L_8Ivxh zoj|1IzRVz>Amjsp^-&6D7Iw_#1>Q;^a@rr;ScgY$?OIq(KKUeR&Kz|zV}sYvhA@?bu& zg~{F>W|!;04i56ETa#1K;C$NJ)1Nje+~IsnTSSvDPxjfX8Zh9pa`b#mdh;LDTj zJDhjV&b@fK7u&um?7Qh%H6uHK6o0 zGkKe^mZkWf!^;GsG#|~0`z_tentM08-yy|u2+x-(P-d>a5p*joWVw6yZsqtX98(2S zKX>i%s#y^nf($^(3pfUPcX!t?zS*i|lnX(XAqXt>p(vYWcvj?N~imDa@`u}{tT~h%Pv9W3m8!2fscz8 zr~7rME@X}ilw{5u56>moPhqJ$%;LKqwrKz<5(Ec&X0~{zp-R(*V-)h5t9#r6|(D*vi|E zx$@#ILtehXU{jb66g9ChieSZ$~FdbrBpoT+^^LSSsyJ3UO!R;JC+-*Bk z2}$Pc%!Dgmm*R{_q+Lew5Jz%Gd`-FLSe<1lcr6q^L)LYLeBbE*sD|=Jl13;i#bYA_ z1HnNXZ(MTM;l0U5AFH3AQO@y_;hvtXpLP`LwlU#&)SdpWld;G6C{FGY2I9C)jj6G* z_R3Jfy+kKeuyQqwuakQ>Fz_6FT<@Lk(nSB;IV(ME%DGJ`P;{a(<1i||E>3tphy`q# zicdwU!Yk8KpnyZG0=iGxq49>!;FR9=+i2TdPFnfe2%M0(ODs6gs5*&`GqLL*!xlPO z`4SML@6v_JnrSvE}rOms!8eGtC{&@^oqjWhb&EougE5m$nL_W4*8hPLzZc9!sq z#^z(^eB=DKTFLmTt;YWWg)k5rP8;alG>!Dxg5`tanz{7&nGsZI7FZ@x|1um?dS+kz zRL8-zfk}&&KmLsFNF7vVTo}WeJiZVuWxKc1cII#-mtUa(LG!%+rc7l}b#iMUVy@tF z=#rbUZzVAv*Jpg326D#Zd?oT}PxWhAq37PG!XZmPZL6|!a;jcAsi~1ti}^oVu1gD} z8dq#mvlqx&kNwBrL~oQkc~#*-t+%&d;ne6xMdAG_v0f}h1i88@lWrR68bFw_*jEOv z%8B}vACkf*GeP&WYlj{^g=P$cB-G50H!QY^ z>EkdHA})7Q2C)V>HJDwONx8oiXg9ZXMrPP)(CJ*r#4>x>*nWM23St&gz*=)ut-Tw@ zkAolMF?P`5DW_9#gS_NIwD5~qgMI%vne|)q3#{eBmoCt_5b&w2jnR4%9`v|m9lfO1 z7i65=|IKAN^Js8+WJDR9%cS72?CGWeZ7=~FdwqKRJy9SLg2{#l`H`C-MVF1@M}=Iq zs)!Qf!M{|!g9DrgNU*ont16v!;&N>CKfQ;}AP!~ayMy`ajy2h*Ol#loBF)wbXvJP5 zq=vf5=iO%nx)@vfS=R3D^&0PGf z<~yFMt9Rt&*E;q$Scj_GdLuP^#y@uwdS`-s3*R{#7d_eJV?)_{i#$5Ef z3!0rWA5z``K@k$kF@OM%o(r@ySMOm2Kl$WH@LxVc5r&9wikeTGVnB~iicnDqnCagU zCFnokln$0_7_o;o27BdVkGK?>6fYG_$x2*mr_?{V$L;@uGE&C8%RadMzukf2_}4Ul zdzlP7n0WfH+7}mi9?8?)xwCWwLMvl#%|MUPn|%u9116mb-!18oC-~o&2=-Fe^FEUr z`V{61b!56egZD5~NVu%MQhTonG0^x|K>lyn<-r^O;Sr=Z**Kf_(H_5kuj^T}n!U?p ztVi!3ZtC?jzOi{sBBvJffX4aCH+Z>cc0aq7gV5o3w|D~!Hb8T+SF5h)#BNIGt7z=T zz-dFju!_xZhUI?^=crsZWjd28)0TfLvmjGXwDI-`~ppVaHV6+axN zu#*pya&TE)9@~9Xc9PgVEOa%#&t@*Au0OZak)iK$zks(n4{)f|G2sfijLv7+(v!jc z5*M0^IRpW%j4#_Jm$vz z-USMI=~IGdLeh05g{j$F5A&##1I}#TMbFQW9J4F4J$kuyOc*T;l_NZ%p?_5C?|xk# z-OumF4outVGS?Tmy>HM|YgXqv`8McbgQ8}u&Pq9r%2NE+UTx5BSH_Or(h;$osTfpN zzSA<~N5F;7#gW27)1oC6dVIIfyLQ>9{26Unu4o&XsWNrOAgm)lTs4-n^8Z*X^zVbA z2xHBFhNBcBnnSlrTqz#>83lqav=jz~2PU7v)eDU4&zr;-x^?K(&2b603_bBSz8bye zz(@AS94Ad(9({O4$S>|qoJyDTHOiB+8;d1t`#G}o3eP?)lA4cCOnoEzF1J&U$Trh!plCZ5wqt%z} zaNisEP%J76+ThB9>tSm;MB`B?g3CrtUI8M7! z3LIjf2R*G==Qde8?ZpMjJ)Zz&p@L0&V)FFqoQ>n;?Okb!-Sn=Of z)8~hdnTdQM2H8VuCMwxIcK=UuVU zahD+dYeI&cFV-MoO}YH#6`-BJ8LUH-p~KLZzn9D~HQNFe%(*3=JfG}lal4F|BE`(# zqMQ~~JSgAr5ZV!3)G0zmTzQ!xtaBy6u`b`plaoFindP6M2_ltnD3S}6L9y)U0i#la zv&0iq>c-h{jZ`Vs82W$w!)c#Vts4m?sE+ShbY)Ay6rx& z)rHngt6JD;|r56NsQ1L0{;Inl&;>C`pkh^IGjQn%!Ak#y{#y@R(@X}Gx zx70qli?OmNndlffzC9&70vi+pei=BFVa6VtXg)#4VluexM@kiQ z>#M4*UBOBZ@fQLjEty}IW26Bq$*xk{W$XC($EYQe)Cc863Xkt%MVo9wh-DdJ==8!X zU%vUq@GDgSDST?)4^a>0xu!&_ZHr{6NJ}~oI3C7~q2<_tk=;x&&(jw~c9Z1;(BqTh zTOmrnQHC~inT)2{YX@m#LQQnaTl~GVcbV+Wsf!r>!ULh=%UcmCy8cl8lTRIV?CQp= zTKTprOt0ZLNB?Na1>Gh8Hm5Xl;2fs zN=}igIBC=VWj>*I7xf{`B9NM(8)<{N2bo1VMJRg$ml7n43w^qsf$;z&#i_;2n<`hi zaTnyAZhU^;JRI=Z7J;7Pq0FY`7_Uw~m6Jj(G0|2{9+6n29)z~6)p@uv_a$L_vi)yZ zV#cDNGWjp(6JQE|j`>GCeKN%9KFIDT*-3IHi^IW!1Y|Lkh_tWplLQWRdEinyM~fvsONKcSW4pGa##TZpZiG{m&yI^{Kn>yKWBVfg zwBsM^u;!&tE8MD`OSuwWMZy;xz4zBIicJiyqiM}{w%w;E|AV_@&^p7vl>dLD9RD^d zIU>QU`|-%+K&?gFF42jswtHqfcLZ5~_hC>Pu6~a`1G)mFC5+obnw(V@$ z1ehE-Ebm(jEp*$4(T*a?z!x{Fe+m8*38+0+xy5a^V`ubnG;O&mEyV$Xb^W*^VvkylZNn6dqN|EyeS=%hDDr&_h9x%MSSjayoc zfd6^2E{@c%V+`Z`tUY;XQek=0^{v)DB19WN8sq%kx$^oE;~G9BeFJDB>;I|l%HyG2 z`~DQC6=^xAC=^AKea#w`eF-T`$SFIc(oh(bt>f6ThAdgL@7bx8CB~2~29s=M?8{ij z^8W78dCqyB=RBY1egAy_=#$93&2{~L*L{6AuqASV>@Gmr4IICn2iusdUs&pq6XoeI zoZ>sWpUo9?zjNhkbLEzZ`Je7Nx+w?G!JVr-?b4St8t9xdH%@259qB!}zNS}92PqP; zLfbcC!xb-wSK1SG~eJgy?NNnb)B-VAcs)ur2w%>LKceg+pG02?*j zU5}{P?u#?i8jd}(rYKPPkO|FO-Q&+7qRRcQp7mY*4!3C`w`tf`YFfQ^+G(uLDh$9r z=UI_XSsH^n;9@;0r0x&yc@~10Zltv_k;SUd3~^Zd=WAmB{%?YhzigORbZOC_vcnOtqcenZg|bLzdU0j@}O<=7$O6#rFU0(eVDd9T!& zf0tMJjZFXE@9c+ew`*U4P)0h}K#H+hJ*8qn=~!YslinHdaOJ9R0!sWDiO-i7K=q3y z-JmHyX?f)Fy=9#*JvOi6T6)2|e{!YKydp}6lD_%78&3i2`L`&$+_-os<-3Q4Ci}Btk zuRX`5v1?02pm5@Z;5G*-&TJ{@LD zy5o#P5TW%!rAR6!LR332UdnDw~5yJ-uk6*yPW8D$YEs( zDcy(DrJbwwQO?6`4Q7riLoRBtQY__4u^L}xs7aV#T`GG7*ck!D{^5u0_`Nx^q*h_6 zHOHCg+t2liY3ZY2>s}=FNZcBT_MU@m)F78$^ksl11Y9Xv!tOhj|BCa|hOM~uz2I|5 zC0~E5g=GUDeH_9CSt0L~HqVJTBM^af zm)qH2WcP8t#I1sl0|NBK(=zUOvl?`G(suB&%9uV7-rlA*MF(Go&0Pc(?|Q&kGCqD) zfC)CR5nZhJF-E}CTb)l>nl5kxqv|%20tTvGuc!CI)tCRG%ybcW7gEcNquQv&FeH-K zckWA1#BEB)NYzo_bQrCXsIJOmvh~76Rt4KYz>b5-k?PAktETrN>&Ni+9rh%7A8KC2 zb8QWZc2})uk~J6`@U33wg+cQrB*Df@AKM@Z<`)+F-487Qs1V?QYc{8SX%DzXwxT0p z%k6l&ZXm^MhX3V5$-c?m+qZCcgo|(zBj~2SZ3&?c&1-JQ!C{H$X`hD!!w9y`^!9Vi zfh3rCBi2&14V$PB!tEAvR0i97&(m@PyG{YajazbQ`M1o&z!?q!v?V-EG7-x`4Lx&? z#|ht;?aKF?yp30wvn%dhMtD1W1aCEImC2{oBu8%W&Im}`vI7@Z5o$_^&OTga)GJA~ zND9aXhoPt}FhSzdFO)4fe-d-188PhgLVB1WsQF-t_E^LHBRxB=UH8Se&roetRGA)3 z5Za~38-a>&By~5C<(YSl0Ak}SY3kFrd^)`4jKl=PK4Ua>iyz{80fJTLjv((wb#FT_ z4E^c6z<1)dlifccSIn|rM{#jCXzd5NGBuMF9B1zYsH|EU9~B)c4Bv@N4Z( z|8AL`?(i1vxOke2z4Gk+U~@ag3xJhRRqy7c!Id7x8T%cK*}ryodn@#`Uyi3Q5=;e3 zl>5?J%_iW8bTQ?w7|ZbVt_vL8FuoPFwVw^>e(M2WL*;FqkBFF9T229pYLM`5HoNH` z1_}Qicpez#f&4T7Ox-&b4&bJ!`3H;)xU+%q13BQRGmqpbSocQSZllidYLQ9&iQ++1 z_tC6Ayzs5?v zj`Qb7Ql)U>Qvxj4CarFC?yDJ!iYWe z_Tn`<7A+HD{gZgF3`>LV$3%`bK5dNec|5z&&19;2q?)DAl%~Ic>qX^#1hdJgV0pDs z3rx*+3%7|(geRszw+kFw5{ur}ov`cu*f?pe&Qn%E$~&Iq3e|(xDa#nI0mJ<+pqYVV zplgX?)vJW*roIJL{|;st27rT2{)!)vtpHL^$=bkuLrIxgTb+q)7StWB*MgS((+ zEWF3N0Zf?OYOlny!V;kWRBR&*u})B+vw>>}5q^B>gv~(xtI6-`y!wz61Hi2vM`kOM z?gBdPT`@=J9bj70V#p8!L9A;$-kye4pw2ycaJE6gT#o?}I_^%H;)&0FpTTAVZjN6$qKy;>j8tWz-7IuDMfL&RO!VXI;*Wprj?I?z{s?&%ge<@`{V# zxSzFW4+2E0Isk1zy|GdQAW@(qzPf~e`^pFcd^RhOz$Ne@=|d`1FM-#LdgI#_6$u|y za5SghLpo8O#hq1=Uq1GJ>AEva8-<(la8}H@`~;310#lgq?@g--io&efcMcuB)skZsHWRwV=L6*m4dAPv=IXLz3S3%YxIfq*cmeVR zn4ZgBb8r(1l`Pqd8M$(-=m;=}Mr+kzq$KSID}(5N7XG_83EqRD5zrvof;?q^u@88+ zk&A<>2tj~LJjur7NkMZv=fJ5g<9%?1y>L<`&9!Bn4)TuMj^hH{GcK!V8oVJaiSGbg z>C19AWTCgscAKH8KU#fS6m)f+JkqqpBJFV~8`+Npe!F)=$kz~A2= zy(~wWEXp=24RY|H5GMP}!vGPzo@b(g#bSE|M@L6nqJ_sZx8g21a@sFQGrh7<04Ij0 z@5BAutnJ>$GI4g491G4uqNC#dUnuRbl2?*A98pB4f$TZ7rX4xq`g2gNZ_Mne2{%W? z>kZr#^5`=wZ{-*i`9fyRVj0BMY{?#wS!6sQyK)kxB|S%*S2e${c72o|0ZdSzt6iP@ z#t!fE+2f;NoM&WYwBzj4p!AcH@nd6S#T!Pd+?pAi(5avmcivX#^QW{#OCg?@O&;0@Se=Zo;KPX)7-apOoyPgUjwDLC- z$T4P&lJolv>%=+}V5#rHIHFq}xqpcHM~LyC<2r9PMq|Jz}%vuDpLPkEibTSqTG z3n;5;(Vu9f({~c2P1XmoG&hBDHR18%ap`&)+fr{LQ0UyI-oqVI5w1TL`+p@2_wbOo zbkBgP#b4CrH{|Rq5);3~xE%(mHg~ndU)pR=)%0l+-EEKCs|Bq<9vqlC{dLP_WiI3M)n7l^HRmAxW^xhCgH2D_5y9; zIv=N1KFfn~h1=Yf=?YSAuKnM`c7Q;es%?jPwDtA5Xl(8iys9#g4T(HpD-hRtUQ|b% zlwy(btipgxlvFK`*&F$PR8Z%NCg2-NYd5CQ{LP1C!jR*r1$N>jGYo7}(A_FH9S%&9 zrcJl2*92W7AmRqE?RxbHe~6Y*?kja{^Lblqc`u}#gXZV&Z!XAfAw&xDoI11)CYUQ!H zkPt14mDEkw937Y2Dj(?hel(>tTk6sLX{dhYV0jT989CqYh)39Pw$|2Wo9nBPYbI>j zdcvJtl+X)8jWfsSgxuF3)~w+b$Qvw))wxHsmKEN>vVrP zczHlKw%UDwHKnSmisWHnU{JOANez_M$lkVG$-QC4J_2ENDbE984mf}wfSWl`2twNi zT}Zruw?7wmU^Oa5r>3O5pU$`tvlxl7#K)(CT>v~C&~-OJh>`^4zFxR+!AT2O@W7bs z$i8QBaT+HXZ?(R-fCQh+6D>nG=h(I&1}#XyX;Oc4inxiJ{w^`-z4!3vBFh8i<>gLV zsix&i-A1e99-EfG@SCXX>Kjab?zw;e^B+a2lD6_doWAJUyVMsJQF*qx`!P%gXejaYD={4H#02`;ccofp@NO`sK zGuRndtc0s;%7W!vw$0hypv51wl^)(y+u10}xQF&E4^MJZQW9YUFH1R(5TOXfO))9w z=@jT-U0FADO-+fI79Ubl-a0W_*m7;+_Gdm8%n3V~mMS*}Vq#)e`p0D(v^>^2YM#H& z0ph~DcM9itcrtQwMq%FZVlWu2D3-AJ8tt(@%oZ(X&)kuwL29-poMWjbw@S_ALjgB& zUp22;uAb4>)9bp?QL5oU0!Nicl&R9y_F(t-;BxXg-;CzCnBBML;I{EkOGSym(9JO_ zoqu@%`-(qpK#u#K#*PUvf2gt}Jo#yVCu9Uwnvg1T6$6=5SzRXu)n+!jjT|z-!h87p z^R(eqod#Z`*RLR`Ez5RGyk?GmsYMvS*yI+MC|)i8+=Zl?(VbINq|0kkr7yG8sf!iW zYfx@jF3)pc%98tg;5ST->kK5d&S3}@m@LB*8@--QkJTs-?X7wKtxsGFm?wjaeY#pQsj>^v_{9$* z6y6IopBml`2}n6j-U8DUW5P|oqdYfq?+{+wi?wEZsH6o!s?#leybMs5m}`l6)2+1| zu$r*%3Ag8}j*7W60R))GyIF6o&X4vx6R}PjU4o$X1!Bk4)D#LFRSF+1Sfptspqt&| z*rO|Cz&YjxKSv~9Sat<}CoG__go7ZSQ zQy)N=4ef$}K5I0(UVu)_VXy^OFjFywQ`zfu5zTomO*Tog-T(WZ`ar9vAT%SnVR(qR zwLwG*m9N<>#Oy75tuaV7kq2+hXMj6rzp` zVv}o)s##3U{V?u9DfN)DB4Ok!+-2!Fn>w?hFhRjR{&WC4g{1cR9!Gy$D3??zl)F?5 zlw*25XxxX}P5$u353ivv@vX%oqu5sT3&>Qw$q zAFKvutzceHGnChd!-3)zubF(`9(Sk`e8ulrpgLjoFP-v7hjVE(FLY&T+T<6!JvdUc2DrO2JRYedNCg3e5`4I59Tl$7V6o_zWz#kd})S7ZhZWj7t&C`pfRExXD7v`Os6lxsGD7UqCI_oyx7P7nBcoBKV+TA|Xn=(@Jkk^f zQ~HqSQIm&{w^o9;z5oGI24?RVOc?NBa;lzzAh?zqEM)~uwD7OAlOKX{dHDvJkdd2f z(Vlb#a#Q8LAR%P1M4&whT?EF2XP(CfNqS?kf>PXo70C9r_nxHXdi&VS$JNSHszzXSERFt!ZTspk8 z*PM#F1!R=67T^!AcBadINKpxE#N#bt?Q`+`Woej!$io40>jJD~;+9A~&ViKoT(a^? zO1r~2HNGOX0Q$vg=D?j-jg13yN$Rm;f&Kmcxm)&q#Tlge-06NNf_(s+Ts(4-5L`J2 zErOA57nltkRoHXS9^f4Ki~2eVj{{kV%?-NFAb)lgEV1>NddQTNl&p8iZ5(D{VR4&> zyfVWuL0IfCuu3-uyDxGS78b7b_0-gdo>6;xnSEtzi#*kq+RE=aJR4P+a`tBR@rS?n zO<&gbrZ*dAR)2EkyzgVZEPeIO9Uo~4pWppb-+#=Ckyf6*kn@J!uLlbl!uZhHdpB>X zNX&bUKNgRxYks6fx!daM8q1{>pVDPBy12MFeL+g9xxT($uIE#4Z**8#m>n9OW|C)V zZhnS?gJW4!1-0UF@2CBqQawFAkJc8ggMxxS*@=anmUCZMF6wO|lbzDi(`Rr*0-ybOtlV_T7J!_Rb zWn^Jt!AdSbN$-<;Npm+nD~qSZkavbyt5t1+@9NTvjEb76hjZ)Z^$1H!#;B%-!q3vv z)495AL=$AOAK_oZVq%eGGTCi&{Q|r&d?%6Aa;`VWiaQ9w7%g=mT0D3lBImK$^7gH~ zub-c=sA$CI=4Suk;MkWhC*c;Y9USmOLuPz@d_uCa@wvIVlhe~3p|*V@_&ePryz??)f4&YSb`^A}ZC#=;fal*Alh zlO2J<#l*_my1D7@g)Pb)`#-ms1~ymh+`9M}5BG&q NxuSVFSK-!^{{fq-$;AKw literal 0 HcmV?d00001 diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index fd206aacd..084f76d0b 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -13,6 +13,7 @@ ** xref:erc721.adoc[ERC721] ** xref:erc777.adoc[ERC777] ** xref:erc1155.adoc[ERC1155] +** xref:erc4626.adoc[ERC4626] * xref:governance.adoc[Governance] diff --git a/docs/modules/ROOT/pages/erc4626.adoc b/docs/modules/ROOT/pages/erc4626.adoc new file mode 100644 index 000000000..11c13ca95 --- /dev/null +++ b/docs/modules/ROOT/pages/erc4626.adoc @@ -0,0 +1,193 @@ += ERC4626 +:stem: latexmath + +https://eips.ethereum.org/EIPS/eip-4626[ERC4626] is an extension of xref:erc20.adoc[ERC20] that proposes a standard interface for token vaults. This standard interface can be used by widely different contracts (including lending markets, aggregators, and intrinsically interest bearing tokens), which brings a number of subtleties. Navigating these potential issues is essential to implementing a compliant and composable token vault. + +We provide a base implementation of ERC4626 that includes a simple vault. This contract is designed in a way that allows developers to easily re-configure the vault's behavior, with minimal overrides, while staying compliant. In this guide, we will discuss some security considerations that affect ERC4626. We will also discuss common customizations of the vault. + +[[inflation-attack]] +== Security concern: Inflation attack + +=== Visualizing the vault + +In exchange for the assets deposited into an ERC4626 vault, a user receives shares. These shares can later be burned to redeem the corresponding underlying assets. The number of shares a user gets depends on the amount of assets they put in and on the exchange rate of the vault. This exchange rate is defined by the current liquidity held by the vault. + +- If a vault has 100 tokens to back 200 shares, then each share is worth 0.5 assets. +- If a vault has 200 tokens to back 100 shares, then each share is worth 2.0 assets. + +In other words, the exchange rate can be defined as the slope of the line that passes through the origin and the current number of assets and shares in the vault. Deposits and withdrawals move the vault in this line. + +image::erc4626-rate-linear.png[Exchange rates in linear scale] + +When plotted in log-log scale, the rate is defined similarly, but appears differently (because the point (0,0) is infinitely far away). Rates are represented by "diagonal" lines with different offsets. + +image::erc4626-rate-loglog.png[Exchange rates in logarithmic scale] + +In such a reprentation, widely different rates can be clearly visible in the same graph. This wouldn't be the case in linear scale. + +image::erc4626-rate-loglogext.png[More exchange rates in logarithmic scale] + +=== The attack + +When depositing tokens, the number of shares a user gets is rounded down. This rounding takes away value from the user in favor or the vault (i.e. in favor of all the current share holders). This rounding is often negligible because of the amount at stake. If you deposit 1e9 shares worth of tokens, the rounding will have you lose at most 0.0000001% of your deposit. However if you deposit 10 shares worth of tokens, you could lose 10% of your deposit. Even worse, if you deposit <1 share worth of tokens, then you get 0 shares, and you basically made a donation. + +For a given amount of assets, the more shares you receive the safer you are. If you want to limit your losses to at most 1%, you need to receive at least 100 shares. + +image::erc4626-deposit.png[Depositing assets] + +In the figure we can see that for a given deposit of 500 assets, the number of shares we get and the corresponding rounding losses depend on the exchange rate. If the exchange rate is that of the orange curve, we are getting less than a share, so we lose 100% of our deposit. However, if the exchange rate is that of the green curve, we get 5000 shares, which limits our rounding losses to at most 0.02%. + +image::erc4626-mint.png[Minting shares] + +Symmetrically, if we focus on limiting our losses to a maximum of 0.5%, we need to get at least 200 shares. With the green exchange rate that requires just 20 tokens, but with the orange rate that requires 200000 tokens. + +We can clearly see that that the blue and green curves correspond to vaults that are safer than the yellow and orange curves. + +The idea of an inflation attack is that an attacker can donate assets to the vault to move the rate curve to the right, and make the vault unsafe. + +image::erc4626-attack.png[Inflation attack without protection] + +Figure 6 shows how an attacker can manipulate the rate of an empty vault. First the attacker must deposit a small amount of tokens (1 token) and follow up with a donation of 1e5 tokens directly to the vault to move the exchange rate "right". This puts the vault in a state where any deposit smaller than 1e5 would be completely lost to the vault. Given that the attacker is the only share holder (from their donation), the attacker would steal all the tokens deposited. + +An attacker would typically wait for a user to do the first deposit into the vault, and would frontrun that operation with the attack described above. The risk is low, and the size of the "donation" required to manipulate the vault is equivalent to the size of the deposit that is being attacked. + +In math that gives: + +- stem:[a_0] the attacker deposit +- stem:[a_1] the attacker donation +- stem:[u] the user deposit + +[%header,cols=4*] +|=== +| +| Assets +| Shares +| Rate + +| initial +| stem:[0] +| stem:[0] +| - + +| after attacker's deposit +| stem:[a_0] +| stem:[a_0] +| stem:[1] + +| after attacker's donation +| stem:[a_0+a_1] +| stem:[a_0] +| stem:[\frac{a_0}{a_0+a_1}] +|=== + +This means a deposit of stem:[u] will give stem:[\frac{u \times a_0}{a_0 + a_1}] shares. + +For the attacker to dilute that deposit to 0 shares, causing the user to lose all its deposit, it must ensure that + +[stem] +++++ +\frac{u \times a_0}{a_0+a_1} < 1 \iff u < 1 + \frac{a_1}{a_0} +++++ + +Using stem:[a_0 = 1] and stem:[a_1 = u] is enough. So the attacker only needs stem:[u+1] assets to perform a successful attack. + +It is easy to generalize the above results to scenarios where the attacker is going after a smaller fraction of the user's deposit. In order to target stem:[\frac{u}{n}], the user needs to suffer rounding of a similar fraction, which means the user must receive at most stem:[n] shares. This results in: + +[stem] +++++ +\frac{u \times a_0}{a_0+a_1} < n \iff \frac{u}{n} < 1 + \frac{a_1}{a_0} +++++ + +In this scenario, the attack is stem:[n] times less powerful (in how much it is stealing) and costs stem:[n] times less to execute. In both cases, the amount of funds the attacker needs to commit is equivalent to its potential earnings. + +=== Defending with a virtual offset + +The defense we propose consists of two parts: + +- Use an offset between the "precision" of the representation of shares and assets. Said otherwise, we use more decimal places to represent the shares than the underlying token does to represent the assets. +- Include virtual shares and virtual assets in the exchange rate computation. These virtual assets enforce the conversion rate when the vault is empty. + +These two parts work together in enforcing the security of the vault. First, the increased precision corresponds to a high rate, which we saw is safer as it reduces the rounding error when computing the amount of shares. Second, the virtual assets and shares (in addition to simplifying a lot of the computations) capture part of the donation, making it unprofitable for a developer to perform an attack. + + +Following the previous math definitions, we have: + +- stem:[\delta] the vault offset +- stem:[a_0] the attacker deposit +- stem:[a_1] the attacker donation +- stem:[u] the user deposit + +[%header,cols=4*] +|=== +| +| Assets +| Shares +| Rate + +| initial +| stem:[1] +| stem:[10^\delta] +| stem:[10^\delta] + +| after attacker's deposit +| stem:[1+a_0] +| stem:[10^\delta \times (1+a_0)] +| stem:[10^\delta] + +| after attacker's donation +| stem:[1+a_0+a_1] +| stem:[10^\delta \times (1+a_0)] +| stem:[10^\delta \times \frac{1+a_0}{1+a_0+a_1}] +|=== + +One important thing to note is that the attacker only owns a fraction stem:[\frac{a_0}{1 + a_0}] of the shares, so when doing the donation, he will only be able to recover that fraction stem:[\frac{a_1 \times a_0}{1 + a_0}] of the donation. The remaining stem:[\frac{a_1}{1+a_0}] are captured by the vault. + +[stem] +++++ +\mathit{loss} = \frac{a_1}{1+a_0} +++++ + +When the user deposits stem:[u], he receives + +[stem] +++++ +10^\delta \times u \times \frac{1+a_0}{1+a_0+a_1} +++++ + +For the attacker to dilute that deposit to 0 shares, causing the user to lose all its deposit, it must ensure that + +[stem] +++++ +10^\delta \times u \times \frac{1+a_0}{1+a_0+a_1} < 1 +++++ + +[stem] +++++ +\iff 10^\delta \times u < \frac{1+a_0+a_1}{1+a_0} +++++ + +[stem] +++++ +\iff 10^\delta \times u < 1 + \frac{a_1}{1+a_0} +++++ + +[stem] +++++ +\iff 10^\delta \times u \le \mathit{loss} +++++ + +- If the offset is 0, the attacker loss is at least equal to the user's deposit. +- If the offset is greater than 0, the attacker will have to suffer losses that are orders of magnitude bigger than the amount of value that can hypothetically be stolen from the user. + +This shows that even with an offset of 0, the virtual shares and assets make this attack non profitable for the attacker. Bigger offsets increase the security even further by making any attack on the user extremely wasteful. + +The following figure shows how the offset impacts the initial rate and limits the ability of an attacker with limited funds to inflate it effectively. + +image::erc4626-attack-3a.png[Inflation attack without offset=3] +stem:[\delta = 3], stem:[a_0 = 1], stem:[a_1 = 10^5] + +image::erc4626-attack-3b.png[Inflation attack without offset=3 and an attacker deposit that limits its losses] +stem:[\delta = 3], stem:[a_0 = 100], stem:[a_1 = 10^5] + +image::erc4626-attack-6.png[Inflation attack without offset=6] +stem:[\delta = 6], stem:[a_0 = 1], stem:[a_1 = 10^5] diff --git a/test/token/ERC20/extensions/ERC4626.t.sol b/test/token/ERC20/extensions/ERC4626.t.sol index 3d7dd4a3e..03786b271 100644 --- a/test/token/ERC20/extensions/ERC4626.t.sol +++ b/test/token/ERC20/extensions/ERC4626.t.sol @@ -15,22 +15,4 @@ contract ERC4626StdTest is ERC4626Test { _vaultMayBeEmpty = false; _unlimitedAmount = true; } - - // solhint-disable-next-line func-name-mixedcase - function test_RT_mint_withdraw(ERC4626Test.Init memory init, uint256 shares) public override { - // There is an edge case where we currently behave different than the property tests, - // when all assets are lost to negative yield. - - // Sum all initially deposited assets. - int256 initAssets = 0; - for (uint256 i = 0; i < init.share.length; i++) { - vm.assume(init.share[i] <= uint256(type(int256).max - initAssets)); - initAssets += SafeCast.toInt256(init.share[i]); - } - - // Reject tests where the yield loses all assets from the vault. - vm.assume(init.yield > -initAssets); - - super.test_RT_mint_withdraw(init, shares); - } } diff --git a/test/token/ERC20/extensions/ERC4626.test.js b/test/token/ERC20/extensions/ERC4626.test.js index 5ed2aa132..0c67a2fc7 100644 --- a/test/token/ERC20/extensions/ERC4626.test.js +++ b/test/token/ERC20/extensions/ERC4626.test.js @@ -1,34 +1,16 @@ -const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); const { expect } = require('chai'); const ERC20Decimals = artifacts.require('$ERC20DecimalsMock'); const ERC4626 = artifacts.require('$ERC4626'); -const ERC4626Decimals = artifacts.require('$ERC4626DecimalsMock'); - -const parseToken = token => new BN(token).mul(new BN('1000000000000')); -const parseShare = share => new BN(share).mul(new BN('1000000000000000000')); +const ERC4626OffsetMock = artifacts.require('$ERC4626OffsetMock'); contract('ERC4626', function (accounts) { const [holder, recipient, spender, other, user1, user2] = accounts; const name = 'My Token'; const symbol = 'MTKN'; - - beforeEach(async function () { - this.token = await ERC20Decimals.new(name, symbol, 12); - this.vault = await ERC4626Decimals.new(name + ' Vault', symbol + 'V', this.token.address, 18); - - await this.token.$_mint(holder, web3.utils.toWei('100')); - await this.token.approve(this.vault.address, constants.MAX_UINT256, { from: holder }); - await this.vault.approve(spender, constants.MAX_UINT256, { from: holder }); - }); - - it('metadata', async function () { - expect(await this.vault.name()).to.be.equal(name + ' Vault'); - expect(await this.vault.symbol()).to.be.equal(symbol + 'V'); - expect(await this.vault.decimals()).to.be.bignumber.equal('18'); - expect(await this.vault.asset()).to.be.equal(this.token.address); - }); + const decimals = web3.utils.toBN(18); it('inherit decimals if from asset', async function () { for (const decimals of [0, 9, 12, 18, 36].map(web3.utils.toBN)) { @@ -38,372 +20,378 @@ contract('ERC4626', function (accounts) { } }); - describe('empty vault: no assets & no shares', function () { - it('status', async function () { - expect(await this.vault.totalAssets()).to.be.bignumber.equal('0'); - }); + for (const offset of [0, 6, 18].map(web3.utils.toBN)) { + const parseToken = token => web3.utils.toBN(10).pow(decimals).muln(token); + const parseShare = share => web3.utils.toBN(10).pow(decimals.add(offset)).muln(share); - it('deposit', async function () { - expect(await this.vault.maxDeposit(holder)).to.be.bignumber.equal(constants.MAX_UINT256); - expect(await this.vault.previewDeposit(parseToken(1))).to.be.bignumber.equal(parseShare(1)); + const virtualAssets = web3.utils.toBN(1); + const virtualShares = web3.utils.toBN(10).pow(offset); - const { tx } = await this.vault.deposit(parseToken(1), recipient, { from: holder }); + describe(`offset: ${offset}`, function () { + beforeEach(async function () { + this.token = await ERC20Decimals.new(name, symbol, decimals); + this.vault = await ERC4626OffsetMock.new(name + ' Vault', symbol + 'V', this.token.address, offset); - await expectEvent.inTransaction(tx, this.token, 'Transfer', { - from: holder, - to: this.vault.address, - value: parseToken(1), + await this.token.$_mint(holder, constants.MAX_INT256); // 50% of maximum + await this.token.approve(this.vault.address, constants.MAX_UINT256, { from: holder }); + await this.vault.approve(spender, constants.MAX_UINT256, { from: holder }); }); - await expectEvent.inTransaction(tx, this.vault, 'Transfer', { - from: constants.ZERO_ADDRESS, - to: recipient, - value: parseShare(1), + it('metadata', async function () { + expect(await this.vault.name()).to.be.equal(name + ' Vault'); + expect(await this.vault.symbol()).to.be.equal(symbol + 'V'); + expect(await this.vault.decimals()).to.be.bignumber.equal(decimals.add(offset)); + expect(await this.vault.asset()).to.be.equal(this.token.address); + }); + + describe('empty vault: no assets & no shares', function () { + it('status', async function () { + expect(await this.vault.totalAssets()).to.be.bignumber.equal('0'); + }); + + it('deposit', async function () { + expect(await this.vault.maxDeposit(holder)).to.be.bignumber.equal(constants.MAX_UINT256); + expect(await this.vault.previewDeposit(parseToken(1))).to.be.bignumber.equal(parseShare(1)); + + const { tx } = await this.vault.deposit(parseToken(1), recipient, { from: holder }); + + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: holder, + to: this.vault.address, + value: parseToken(1), + }); + + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: constants.ZERO_ADDRESS, + to: recipient, + value: parseShare(1), + }); + }); + + it('mint', async function () { + expect(await this.vault.maxMint(holder)).to.be.bignumber.equal(constants.MAX_UINT256); + expect(await this.vault.previewMint(parseShare(1))).to.be.bignumber.equal(parseToken(1)); + + const { tx } = await this.vault.mint(parseShare(1), recipient, { from: holder }); + + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: holder, + to: this.vault.address, + value: parseToken(1), + }); + + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: constants.ZERO_ADDRESS, + to: recipient, + value: parseShare(1), + }); + }); + + it('withdraw', async function () { + expect(await this.vault.maxWithdraw(holder)).to.be.bignumber.equal('0'); + expect(await this.vault.previewWithdraw('0')).to.be.bignumber.equal('0'); + + const { tx } = await this.vault.withdraw('0', recipient, holder, { from: holder }); + + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.vault.address, + to: recipient, + value: '0', + }); + + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: holder, + to: constants.ZERO_ADDRESS, + value: '0', + }); + }); + + it('redeem', async function () { + expect(await this.vault.maxRedeem(holder)).to.be.bignumber.equal('0'); + expect(await this.vault.previewRedeem('0')).to.be.bignumber.equal('0'); + + const { tx } = await this.vault.redeem('0', recipient, holder, { from: holder }); + + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.vault.address, + to: recipient, + value: '0', + }); + + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: holder, + to: constants.ZERO_ADDRESS, + value: '0', + }); + }); + }); + + describe('inflation attack: offset price by direct deposit of assets', function () { + beforeEach(async function () { + // Donate 1 token to the vault to offset the price + await this.token.$_mint(this.vault.address, parseToken(1)); + }); + + it('status', async function () { + expect(await this.vault.totalSupply()).to.be.bignumber.equal('0'); + expect(await this.vault.totalAssets()).to.be.bignumber.equal(parseToken(1)); + }); + + /** + * | offset | deposited assets | redeemable assets | + * |--------|----------------------|----------------------| + * | 0 | 1.000000000000000000 | 0. | + * | 6 | 1.000000000000000000 | 0.999999000000000000 | + * | 18 | 1.000000000000000000 | 0.999999999999999999 | + * + * Attack is possible, but made difficult by the offset. For the attack to be successful + * the attacker needs to frontrun a deposit 10**offset times bigger than what the victim + * was trying to deposit + */ + it('deposit', async function () { + const effectiveAssets = await this.vault.totalAssets().then(x => x.add(virtualAssets)); + const effectiveShares = await this.vault.totalSupply().then(x => x.add(virtualShares)); + + const depositAssets = parseToken(1); + const expectedShares = depositAssets.mul(effectiveShares).div(effectiveAssets); + + expect(await this.vault.maxDeposit(holder)).to.be.bignumber.equal(constants.MAX_UINT256); + expect(await this.vault.previewDeposit(depositAssets)).to.be.bignumber.equal(expectedShares); + + const { tx } = await this.vault.deposit(depositAssets, recipient, { from: holder }); + + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: holder, + to: this.vault.address, + value: depositAssets, + }); + + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: constants.ZERO_ADDRESS, + to: recipient, + value: expectedShares, + }); + }); + + /** + * | offset | deposited assets | redeemable assets | + * |--------|----------------------|----------------------| + * | 0 | 1000000000000000001. | 1000000000000000001. | + * | 6 | 1000000000000000001. | 1000000000000000001. | + * | 18 | 1000000000000000001. | 1000000000000000001. | + * + * Using mint protects against inflation attack, but makes minting shares very expensive. + * The ER20 allowance for the underlying asset is needed to protect the user from (too) + * large deposits. + */ + it('mint', async function () { + const effectiveAssets = await this.vault.totalAssets().then(x => x.add(virtualAssets)); + const effectiveShares = await this.vault.totalSupply().then(x => x.add(virtualShares)); + + const mintShares = parseShare(1); + const expectedAssets = mintShares.mul(effectiveAssets).div(effectiveShares); + + expect(await this.vault.maxMint(holder)).to.be.bignumber.equal(constants.MAX_UINT256); + expect(await this.vault.previewMint(mintShares)).to.be.bignumber.equal(expectedAssets); + + const { tx } = await this.vault.mint(mintShares, recipient, { from: holder }); + + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: holder, + to: this.vault.address, + value: expectedAssets, + }); + + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: constants.ZERO_ADDRESS, + to: recipient, + value: mintShares, + }); + }); + + it('withdraw', async function () { + expect(await this.vault.maxWithdraw(holder)).to.be.bignumber.equal('0'); + expect(await this.vault.previewWithdraw('0')).to.be.bignumber.equal('0'); + + const { tx } = await this.vault.withdraw('0', recipient, holder, { from: holder }); + + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.vault.address, + to: recipient, + value: '0', + }); + + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: holder, + to: constants.ZERO_ADDRESS, + value: '0', + }); + }); + + it('redeem', async function () { + expect(await this.vault.maxRedeem(holder)).to.be.bignumber.equal('0'); + expect(await this.vault.previewRedeem('0')).to.be.bignumber.equal('0'); + + const { tx } = await this.vault.redeem('0', recipient, holder, { from: holder }); + + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.vault.address, + to: recipient, + value: '0', + }); + + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: holder, + to: constants.ZERO_ADDRESS, + value: '0', + }); + }); + }); + + describe('full vault: assets & shares', function () { + beforeEach(async function () { + // Add 1 token of underlying asset and 100 shares to the vault + await this.token.$_mint(this.vault.address, parseToken(1)); + await this.vault.$_mint(holder, parseShare(100)); + }); + + it('status', async function () { + expect(await this.vault.totalSupply()).to.be.bignumber.equal(parseShare(100)); + expect(await this.vault.totalAssets()).to.be.bignumber.equal(parseToken(1)); + }); + + /** + * | offset | deposited assets | redeemable assets | + * |--------|--------------------- |----------------------| + * | 0 | 1.000000000000000000 | 0.999999999999999999 | + * | 6 | 1.000000000000000000 | 0.999999999999999999 | + * | 18 | 1.000000000000000000 | 0.999999999999999999 | + * + * Virtual shares & assets captures part of the value + */ + it('deposit', async function () { + const effectiveAssets = await this.vault.totalAssets().then(x => x.add(virtualAssets)); + const effectiveShares = await this.vault.totalSupply().then(x => x.add(virtualShares)); + + const depositAssets = parseToken(1); + const expectedShares = depositAssets.mul(effectiveShares).div(effectiveAssets); + + expect(await this.vault.maxDeposit(holder)).to.be.bignumber.equal(constants.MAX_UINT256); + expect(await this.vault.previewDeposit(depositAssets)).to.be.bignumber.equal(expectedShares); + + const { tx } = await this.vault.deposit(depositAssets, recipient, { from: holder }); + + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: holder, + to: this.vault.address, + value: depositAssets, + }); + + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: constants.ZERO_ADDRESS, + to: recipient, + value: expectedShares, + }); + }); + + /** + * | offset | deposited assets | redeemable assets | + * |--------|--------------------- |----------------------| + * | 0 | 0.010000000000000001 | 0.010000000000000000 | + * | 6 | 0.010000000000000001 | 0.010000000000000000 | + * | 18 | 0.010000000000000001 | 0.010000000000000000 | + * + * Virtual shares & assets captures part of the value + */ + it('mint', async function () { + const effectiveAssets = await this.vault.totalAssets().then(x => x.add(virtualAssets)); + const effectiveShares = await this.vault.totalSupply().then(x => x.add(virtualShares)); + + const mintShares = parseShare(1); + const expectedAssets = mintShares.mul(effectiveAssets).div(effectiveShares).addn(1); // add for the rounding + + expect(await this.vault.maxMint(holder)).to.be.bignumber.equal(constants.MAX_UINT256); + expect(await this.vault.previewMint(mintShares)).to.be.bignumber.equal(expectedAssets); + + const { tx } = await this.vault.mint(mintShares, recipient, { from: holder }); + + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: holder, + to: this.vault.address, + value: expectedAssets, + }); + + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: constants.ZERO_ADDRESS, + to: recipient, + value: mintShares, + }); + }); + + it('withdraw', async function () { + const effectiveAssets = await this.vault.totalAssets().then(x => x.add(virtualAssets)); + const effectiveShares = await this.vault.totalSupply().then(x => x.add(virtualShares)); + + const withdrawAssets = parseToken(1); + const expectedShares = withdrawAssets.mul(effectiveShares).div(effectiveAssets).addn(1); // add for the rounding + + expect(await this.vault.maxWithdraw(holder)).to.be.bignumber.equal(withdrawAssets); + expect(await this.vault.previewWithdraw(withdrawAssets)).to.be.bignumber.equal(expectedShares); + + const { tx } = await this.vault.withdraw(withdrawAssets, recipient, holder, { from: holder }); + + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.vault.address, + to: recipient, + value: withdrawAssets, + }); + + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: holder, + to: constants.ZERO_ADDRESS, + value: expectedShares, + }); + }); + + it('withdraw with approval', async function () { + await expectRevert( + this.vault.withdraw(parseToken(1), recipient, holder, { from: other }), + 'ERC20: insufficient allowance', + ); + + await this.vault.withdraw(parseToken(1), recipient, holder, { from: spender }); + }); + + it('redeem', async function () { + expect(await this.vault.maxRedeem(holder)).to.be.bignumber.equal(parseShare(100)); + expect(await this.vault.previewRedeem(parseShare(100))).to.be.bignumber.equal(parseToken(1)); + + const { tx } = await this.vault.redeem(parseShare(100), recipient, holder, { from: holder }); + + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.vault.address, + to: recipient, + value: parseToken(1), + }); + + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: holder, + to: constants.ZERO_ADDRESS, + value: parseShare(100), + }); + }); + + it('redeem with approval', async function () { + await expectRevert( + this.vault.redeem(parseShare(100), recipient, holder, { from: other }), + 'ERC20: insufficient allowance', + ); + + await this.vault.redeem(parseShare(100), recipient, holder, { from: spender }); + }); }); }); - - it('mint', async function () { - expect(await this.vault.maxMint(holder)).to.be.bignumber.equal(constants.MAX_UINT256); - expect(await this.vault.previewMint(parseShare(1))).to.be.bignumber.equal(parseToken(1)); - - const { tx } = await this.vault.mint(parseShare(1), recipient, { from: holder }); - - await expectEvent.inTransaction(tx, this.token, 'Transfer', { - from: holder, - to: this.vault.address, - value: parseToken(1), - }); - - await expectEvent.inTransaction(tx, this.vault, 'Transfer', { - from: constants.ZERO_ADDRESS, - to: recipient, - value: parseShare(1), - }); - }); - - it('withdraw', async function () { - expect(await this.vault.maxWithdraw(holder)).to.be.bignumber.equal('0'); - expect(await this.vault.previewWithdraw('0')).to.be.bignumber.equal('0'); - - const { tx } = await this.vault.withdraw('0', recipient, holder, { from: holder }); - - await expectEvent.inTransaction(tx, this.token, 'Transfer', { - from: this.vault.address, - to: recipient, - value: '0', - }); - - await expectEvent.inTransaction(tx, this.vault, 'Transfer', { - from: holder, - to: constants.ZERO_ADDRESS, - value: '0', - }); - }); - - it('redeem', async function () { - expect(await this.vault.maxRedeem(holder)).to.be.bignumber.equal('0'); - expect(await this.vault.previewRedeem('0')).to.be.bignumber.equal('0'); - - const { tx } = await this.vault.redeem('0', recipient, holder, { from: holder }); - - await expectEvent.inTransaction(tx, this.token, 'Transfer', { - from: this.vault.address, - to: recipient, - value: '0', - }); - - await expectEvent.inTransaction(tx, this.vault, 'Transfer', { - from: holder, - to: constants.ZERO_ADDRESS, - value: '0', - }); - }); - }); - - describe('partially empty vault: assets & no shares', function () { - beforeEach(async function () { - await this.token.$_mint(this.vault.address, parseToken(1)); // 1 token - }); - - it('status', async function () { - expect(await this.vault.totalAssets()).to.be.bignumber.equal(parseToken(1)); - }); - - it('deposit', async function () { - expect(await this.vault.maxDeposit(holder)).to.be.bignumber.equal(constants.MAX_UINT256); - expect(await this.vault.previewDeposit(parseToken(1))).to.be.bignumber.equal(parseShare(1)); - - const { tx } = await this.vault.deposit(parseToken(1), recipient, { from: holder }); - - await expectEvent.inTransaction(tx, this.token, 'Transfer', { - from: holder, - to: this.vault.address, - value: parseToken(1), - }); - - await expectEvent.inTransaction(tx, this.vault, 'Transfer', { - from: constants.ZERO_ADDRESS, - to: recipient, - value: parseShare(1), - }); - }); - - it('mint', async function () { - expect(await this.vault.maxMint(holder)).to.be.bignumber.equal(constants.MAX_UINT256); - expect(await this.vault.previewMint(parseShare(1))).to.be.bignumber.equal(parseToken(1)); - - const { tx } = await this.vault.mint(parseShare(1), recipient, { from: holder }); - - await expectEvent.inTransaction(tx, this.token, 'Transfer', { - from: holder, - to: this.vault.address, - value: parseToken(1), - }); - - await expectEvent.inTransaction(tx, this.vault, 'Transfer', { - from: constants.ZERO_ADDRESS, - to: recipient, - value: parseShare(1), - }); - }); - - it('withdraw', async function () { - expect(await this.vault.maxWithdraw(holder)).to.be.bignumber.equal('0'); - expect(await this.vault.previewWithdraw('0')).to.be.bignumber.equal('0'); - - const { tx } = await this.vault.withdraw('0', recipient, holder, { from: holder }); - - await expectEvent.inTransaction(tx, this.token, 'Transfer', { - from: this.vault.address, - to: recipient, - value: '0', - }); - - await expectEvent.inTransaction(tx, this.vault, 'Transfer', { - from: holder, - to: constants.ZERO_ADDRESS, - value: '0', - }); - }); - - it('redeem', async function () { - expect(await this.vault.maxRedeem(holder)).to.be.bignumber.equal('0'); - expect(await this.vault.previewRedeem('0')).to.be.bignumber.equal('0'); - - const { tx } = await this.vault.redeem('0', recipient, holder, { from: holder }); - - await expectEvent.inTransaction(tx, this.token, 'Transfer', { - from: this.vault.address, - to: recipient, - value: '0', - }); - - await expectEvent.inTransaction(tx, this.vault, 'Transfer', { - from: holder, - to: constants.ZERO_ADDRESS, - value: '0', - }); - }); - }); - - describe('partially empty vault: shares & no assets', function () { - beforeEach(async function () { - await this.vault.$_mint(holder, parseShare(1)); // 1 share - }); - - it('status', async function () { - expect(await this.vault.totalAssets()).to.be.bignumber.equal('0'); - }); - - it('deposit', async function () { - expect(await this.vault.maxDeposit(holder)).to.be.bignumber.equal('0'); - - // Can deposit 0 (max deposit) - const { tx } = await this.vault.deposit(0, recipient, { from: holder }); - - await expectEvent.inTransaction(tx, this.token, 'Transfer', { - from: holder, - to: this.vault.address, - value: '0', - }); - - await expectEvent.inTransaction(tx, this.vault, 'Transfer', { - from: constants.ZERO_ADDRESS, - to: recipient, - value: '0', - }); - - // Cannot deposit more than 0 - await expectRevert.unspecified(this.vault.previewDeposit(parseToken(1))); - await expectRevert( - this.vault.deposit(parseToken(1), recipient, { from: holder }), - 'ERC4626: deposit more than max', - ); - }); - - it('mint', async function () { - expect(await this.vault.maxMint(holder)).to.be.bignumber.equal(constants.MAX_UINT256); - expect(await this.vault.previewMint(parseShare(1))).to.be.bignumber.equal('0'); - - const { tx } = await this.vault.mint(parseShare(1), recipient, { from: holder }); - - await expectEvent.inTransaction(tx, this.token, 'Transfer', { - from: holder, - to: this.vault.address, - value: '0', - }); - - await expectEvent.inTransaction(tx, this.vault, 'Transfer', { - from: constants.ZERO_ADDRESS, - to: recipient, - value: parseShare(1), - }); - }); - - it('withdraw', async function () { - expect(await this.vault.maxWithdraw(holder)).to.be.bignumber.equal('0'); - expect(await this.vault.previewWithdraw('0')).to.be.bignumber.equal('0'); - await expectRevert.unspecified(this.vault.previewWithdraw('1')); - - const { tx } = await this.vault.withdraw('0', recipient, holder, { from: holder }); - - await expectEvent.inTransaction(tx, this.token, 'Transfer', { - from: this.vault.address, - to: recipient, - value: '0', - }); - - await expectEvent.inTransaction(tx, this.vault, 'Transfer', { - from: holder, - to: constants.ZERO_ADDRESS, - value: '0', - }); - }); - - it('redeem', async function () { - expect(await this.vault.maxRedeem(holder)).to.be.bignumber.equal(parseShare(1)); - expect(await this.vault.previewRedeem(parseShare(1))).to.be.bignumber.equal('0'); - - const { tx } = await this.vault.redeem(parseShare(1), recipient, holder, { from: holder }); - - await expectEvent.inTransaction(tx, this.token, 'Transfer', { - from: this.vault.address, - to: recipient, - value: '0', - }); - - await expectEvent.inTransaction(tx, this.vault, 'Transfer', { - from: holder, - to: constants.ZERO_ADDRESS, - value: parseShare(1), - }); - }); - }); - - describe('full vault: assets & shares', function () { - beforeEach(async function () { - await this.token.$_mint(this.vault.address, parseToken(1)); // 1 tokens - await this.vault.$_mint(holder, parseShare(100)); // 100 share - }); - - it('status', async function () { - expect(await this.vault.totalAssets()).to.be.bignumber.equal(parseToken(1)); - }); - - it('deposit', async function () { - expect(await this.vault.maxDeposit(holder)).to.be.bignumber.equal(constants.MAX_UINT256); - expect(await this.vault.previewDeposit(parseToken(1))).to.be.bignumber.equal(parseShare(100)); - - const { tx } = await this.vault.deposit(parseToken(1), recipient, { from: holder }); - - await expectEvent.inTransaction(tx, this.token, 'Transfer', { - from: holder, - to: this.vault.address, - value: parseToken(1), - }); - - await expectEvent.inTransaction(tx, this.vault, 'Transfer', { - from: constants.ZERO_ADDRESS, - to: recipient, - value: parseShare(100), - }); - }); - - it('mint', async function () { - expect(await this.vault.maxMint(holder)).to.be.bignumber.equal(constants.MAX_UINT256); - expect(await this.vault.previewMint(parseShare(1))).to.be.bignumber.equal(parseToken(1).divn(100)); - - const { tx } = await this.vault.mint(parseShare(1), recipient, { from: holder }); - - await expectEvent.inTransaction(tx, this.token, 'Transfer', { - from: holder, - to: this.vault.address, - value: parseToken(1).divn(100), - }); - - await expectEvent.inTransaction(tx, this.vault, 'Transfer', { - from: constants.ZERO_ADDRESS, - to: recipient, - value: parseShare(1), - }); - }); - - it('withdraw', async function () { - expect(await this.vault.maxWithdraw(holder)).to.be.bignumber.equal(parseToken(1)); - expect(await this.vault.previewWithdraw(parseToken(1))).to.be.bignumber.equal(parseShare(100)); - - const { tx } = await this.vault.withdraw(parseToken(1), recipient, holder, { from: holder }); - - await expectEvent.inTransaction(tx, this.token, 'Transfer', { - from: this.vault.address, - to: recipient, - value: parseToken(1), - }); - - await expectEvent.inTransaction(tx, this.vault, 'Transfer', { - from: holder, - to: constants.ZERO_ADDRESS, - value: parseShare(100), - }); - }); - - it('withdraw with approval', async function () { - await expectRevert( - this.vault.withdraw(parseToken(1), recipient, holder, { from: other }), - 'ERC20: insufficient allowance', - ); - - await this.vault.withdraw(parseToken(1), recipient, holder, { from: spender }); - }); - - it('redeem', async function () { - expect(await this.vault.maxRedeem(holder)).to.be.bignumber.equal(parseShare(100)); - expect(await this.vault.previewRedeem(parseShare(100))).to.be.bignumber.equal(parseToken(1)); - - const { tx } = await this.vault.redeem(parseShare(100), recipient, holder, { from: holder }); - - await expectEvent.inTransaction(tx, this.token, 'Transfer', { - from: this.vault.address, - to: recipient, - value: parseToken(1), - }); - - await expectEvent.inTransaction(tx, this.vault, 'Transfer', { - from: holder, - to: constants.ZERO_ADDRESS, - value: parseShare(100), - }); - }); - - it('redeem with approval', async function () { - await expectRevert( - this.vault.redeem(parseShare(100), recipient, holder, { from: other }), - 'ERC20: insufficient allowance', - ); - - await this.vault.redeem(parseShare(100), recipient, holder, { from: spender }); - }); - }); + } /// Scenario inspired by solmate ERC4626 tests: /// https://github.com/transmissions11/solmate/blob/main/src/test/ERC4626.t.sol @@ -468,8 +456,8 @@ contract('ERC4626', function (accounts) { expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('2000'); expect(await this.vault.balanceOf(user2)).to.be.bignumber.equal('4000'); - expect(await this.vault.convertToAssets(await this.vault.balanceOf(user1))).to.be.bignumber.equal('3000'); - expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('6000'); + expect(await this.vault.convertToAssets(await this.vault.balanceOf(user1))).to.be.bignumber.equal('2999'); // used to be 3000, but virtual assets/shares captures part of the yield + expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('5999'); // used to be 6000, but virtual assets/shares captures part of the yield expect(await this.vault.totalSupply()).to.be.bignumber.equal('6000'); expect(await this.vault.totalAssets()).to.be.bignumber.equal('9000'); @@ -503,7 +491,7 @@ contract('ERC4626', function (accounts) { await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: user2, to: this.vault.address, - value: '3001', + value: '3000', // used to be 3001 }); await expectEvent.inTransaction(tx, this.vault, 'Transfer', { from: constants.ZERO_ADDRESS, @@ -513,10 +501,10 @@ contract('ERC4626', function (accounts) { expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('3333'); expect(await this.vault.balanceOf(user2)).to.be.bignumber.equal('6000'); - expect(await this.vault.convertToAssets(await this.vault.balanceOf(user1))).to.be.bignumber.equal('5000'); + expect(await this.vault.convertToAssets(await this.vault.balanceOf(user1))).to.be.bignumber.equal('4999'); // used to be 5000 expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('9000'); expect(await this.vault.totalSupply()).to.be.bignumber.equal('9333'); - expect(await this.vault.totalAssets()).to.be.bignumber.equal('14001'); + expect(await this.vault.totalAssets()).to.be.bignumber.equal('14000'); // used to be 14001 } // 6. Vault mutates by +3000 tokens @@ -525,10 +513,10 @@ contract('ERC4626', function (accounts) { expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('3333'); expect(await this.vault.balanceOf(user2)).to.be.bignumber.equal('6000'); - expect(await this.vault.convertToAssets(await this.vault.balanceOf(user1))).to.be.bignumber.equal('6071'); - expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('10929'); + expect(await this.vault.convertToAssets(await this.vault.balanceOf(user1))).to.be.bignumber.equal('6070'); // used to be 6071 + expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('10928'); // used to be 10929 expect(await this.vault.totalSupply()).to.be.bignumber.equal('9333'); - expect(await this.vault.totalAssets()).to.be.bignumber.equal('17001'); + expect(await this.vault.totalAssets()).to.be.bignumber.equal('17000'); // used to be 17001 // 7. Alice redeem 1333 shares (2428 assets) { @@ -541,7 +529,7 @@ contract('ERC4626', function (accounts) { await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: this.vault.address, to: user1, - value: '2428', + value: '2427', // used to be 2428 }); expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('2000'); @@ -592,7 +580,7 @@ contract('ERC4626', function (accounts) { expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('0'); expect(await this.vault.balanceOf(user2)).to.be.bignumber.equal('4392'); expect(await this.vault.convertToAssets(await this.vault.balanceOf(user1))).to.be.bignumber.equal('0'); - expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('8001'); + expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('8000'); // used to be 8001 expect(await this.vault.totalSupply()).to.be.bignumber.equal('4392'); expect(await this.vault.totalAssets()).to.be.bignumber.equal('8001'); } @@ -608,7 +596,7 @@ contract('ERC4626', function (accounts) { await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: this.vault.address, to: user2, - value: '8001', + value: '8000', // used to be 8001 }); expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('0'); @@ -616,7 +604,7 @@ contract('ERC4626', function (accounts) { expect(await this.vault.convertToAssets(await this.vault.balanceOf(user1))).to.be.bignumber.equal('0'); expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('0'); expect(await this.vault.totalSupply()).to.be.bignumber.equal('0'); - expect(await this.vault.totalAssets()).to.be.bignumber.equal('0'); + expect(await this.vault.totalAssets()).to.be.bignumber.equal('1'); // used to be 0 } }); }); diff --git a/test/utils/math/Math.t.sol b/test/utils/math/Math.t.sol index 5542baf9d..916136cdd 100644 --- a/test/utils/math/Math.t.sol +++ b/test/utils/math/Math.t.sol @@ -177,7 +177,7 @@ contract MathTest is Test { } // Helpers - function _asRounding(uint8 r) private returns (Math.Rounding) { + function _asRounding(uint8 r) private pure returns (Math.Rounding) { vm.assume(r < uint8(type(Math.Rounding).max)); return Math.Rounding(r); } From 96a2297e15f1a4bbcf470d2d0d6cb9c579c63893 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Fri, 17 Feb 2023 10:26:10 +0100 Subject: [PATCH 039/133] Add IERC4906 interface and use in ERC721 (#4012) Co-authored-by: Francisco Giordano --- .changeset/lovely-dragons-appear.md | 5 +++++ .changeset/thirty-swans-exercise.md | 5 +++++ contracts/interfaces/IERC4906.sol | 19 +++++++++++++++++++ .../ERC721/extensions/ERC721URIStorage.sol | 7 ++++++- .../extensions/ERC721URIStorage.test.js | 8 +++++++- 5 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 .changeset/lovely-dragons-appear.md create mode 100644 .changeset/thirty-swans-exercise.md create mode 100644 contracts/interfaces/IERC4906.sol diff --git a/.changeset/lovely-dragons-appear.md b/.changeset/lovely-dragons-appear.md new file mode 100644 index 000000000..fe538634a --- /dev/null +++ b/.changeset/lovely-dragons-appear.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': minor +--- + +`IERC4906`: Add an interface for ERC-4906 that is now Final. diff --git a/.changeset/thirty-swans-exercise.md b/.changeset/thirty-swans-exercise.md new file mode 100644 index 000000000..a460271b0 --- /dev/null +++ b/.changeset/thirty-swans-exercise.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': minor +--- + +`ERC721URIStorage`: Emit ERC-4906 `MetadataUpdate` in `_setTokenURI`. diff --git a/contracts/interfaces/IERC4906.sol b/contracts/interfaces/IERC4906.sol new file mode 100644 index 000000000..c9eaa1296 --- /dev/null +++ b/contracts/interfaces/IERC4906.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "./IERC165.sol"; +import "./IERC721.sol"; + +/// @title EIP-721 Metadata Update Extension +interface IERC4906 is IERC165, IERC721 { + /// @dev This event emits when the metadata of a token is changed. + /// So that the third-party platforms such as NFT market could + /// timely update the images and related attributes of the NFT. + event MetadataUpdate(uint256 _tokenId); + + /// @dev This event emits when the metadata of a range of tokens is changed. + /// So that the third-party platforms such as NFT market could + /// timely update the images and related attributes of the NFTs. + event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId); +} diff --git a/contracts/token/ERC721/extensions/ERC721URIStorage.sol b/contracts/token/ERC721/extensions/ERC721URIStorage.sol index e83a5ede2..4b919b79e 100644 --- a/contracts/token/ERC721/extensions/ERC721URIStorage.sol +++ b/contracts/token/ERC721/extensions/ERC721URIStorage.sol @@ -4,11 +4,12 @@ pragma solidity ^0.8.0; import "../ERC721.sol"; +import "../../../interfaces/IERC4906.sol"; /** * @dev ERC721 token with storage based token URI management. */ -abstract contract ERC721URIStorage is ERC721 { +abstract contract ERC721URIStorage is IERC4906, ERC721 { using Strings for uint256; // Optional mapping for token URIs @@ -38,6 +39,8 @@ abstract contract ERC721URIStorage is ERC721 { /** * @dev Sets `_tokenURI` as the tokenURI of `tokenId`. * + * Emits {MetadataUpdate}. + * * Requirements: * * - `tokenId` must exist. @@ -45,6 +48,8 @@ abstract contract ERC721URIStorage is ERC721 { function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual { require(_exists(tokenId), "ERC721URIStorage: URI set of nonexistent token"); _tokenURIs[tokenId] = _tokenURI; + + emit MetadataUpdate(tokenId); } /** diff --git a/test/token/ERC721/extensions/ERC721URIStorage.test.js b/test/token/ERC721/extensions/ERC721URIStorage.test.js index c0274c669..0835505e9 100644 --- a/test/token/ERC721/extensions/ERC721URIStorage.test.js +++ b/test/token/ERC721/extensions/ERC721URIStorage.test.js @@ -1,4 +1,4 @@ -const { BN, expectRevert } = require('@openzeppelin/test-helpers'); +const { BN, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); const { expect } = require('chai'); @@ -38,6 +38,12 @@ contract('ERC721URIStorage', function (accounts) { expect(await this.token.tokenURI(firstTokenId)).to.be.equal(sampleUri); }); + it('setting the uri emits an event', async function () { + expectEvent(await this.token.$_setTokenURI(firstTokenId, sampleUri), 'MetadataUpdate', { + _tokenId: firstTokenId, + }); + }); + it('reverts when setting for non existent token id', async function () { await expectRevert( this.token.$_setTokenURI(nonExistentTokenId, sampleUri), From 08d085f2c9cf65552993bc2cf91e7531acb4bc88 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Fri, 17 Feb 2023 17:43:23 +0100 Subject: [PATCH 040/133] Fix ERC4906 compliance of ERC721URIStorage (#4055) Co-authored-by: Francisco --- contracts/token/ERC721/extensions/ERC721URIStorage.sol | 7 +++++++ test/token/ERC721/extensions/ERC721URIStorage.test.js | 5 ++++- test/utils/introspection/SupportsInterface.behavior.js | 6 ++++-- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/contracts/token/ERC721/extensions/ERC721URIStorage.sol b/contracts/token/ERC721/extensions/ERC721URIStorage.sol index 4b919b79e..201b05a81 100644 --- a/contracts/token/ERC721/extensions/ERC721URIStorage.sol +++ b/contracts/token/ERC721/extensions/ERC721URIStorage.sol @@ -15,6 +15,13 @@ abstract contract ERC721URIStorage is IERC4906, ERC721 { // Optional mapping for token URIs mapping(uint256 => string) private _tokenURIs; + /** + * @dev See {IERC165-supportsInterface} + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, IERC165) returns (bool) { + return interfaceId == bytes4(0x49064906) || super.supportsInterface(interfaceId); + } + /** * @dev See {IERC721Metadata-tokenURI}. */ diff --git a/test/token/ERC721/extensions/ERC721URIStorage.test.js b/test/token/ERC721/extensions/ERC721URIStorage.test.js index 0835505e9..60c80066c 100644 --- a/test/token/ERC721/extensions/ERC721URIStorage.test.js +++ b/test/token/ERC721/extensions/ERC721URIStorage.test.js @@ -1,7 +1,8 @@ const { BN, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); - const { expect } = require('chai'); +const { shouldSupportInterfaces } = require('../../../utils/introspection/SupportsInterface.behavior'); + const ERC721URIStorageMock = artifacts.require('$ERC721URIStorageMock'); contract('ERC721URIStorage', function (accounts) { @@ -17,6 +18,8 @@ contract('ERC721URIStorage', function (accounts) { this.token = await ERC721URIStorageMock.new(name, symbol); }); + shouldSupportInterfaces(['0x49064906']); + describe('token URI', function () { beforeEach(async function () { await this.token.$_mint(owner, firstTokenId); diff --git a/test/utils/introspection/SupportsInterface.behavior.js b/test/utils/introspection/SupportsInterface.behavior.js index ba5aca2fc..02d147884 100644 --- a/test/utils/introspection/SupportsInterface.behavior.js +++ b/test/utils/introspection/SupportsInterface.behavior.js @@ -100,20 +100,22 @@ function shouldSupportInterfaces(interfaces = []) { it('supportsInterface uses less than 30k gas', async function () { for (const k of interfaces) { - const interfaceId = INTERFACE_IDS[k]; + const interfaceId = INTERFACE_IDS[k] ?? k; expect(await this.contractUnderTest.supportsInterface.estimateGas(interfaceId)).to.be.lte(30000); } }); it('all interfaces are reported as supported', async function () { for (const k of interfaces) { - const interfaceId = INTERFACE_IDS[k]; + const interfaceId = INTERFACE_IDS[k] ?? k; expect(await this.contractUnderTest.supportsInterface(interfaceId)).to.equal(true); } }); it('all interface functions are in ABI', async function () { for (const k of interfaces) { + // skip interfaces for which we don't have a function list + if (INTERFACES[k] === undefined) continue; for (const fnName of INTERFACES[k]) { const fnSig = FN_SIGNATURES[fnName]; expect(this.contractUnderTest.abi.filter(fn => fn.signature === fnSig).length).to.equal(1); From 7ac4349710d3b242dd3ceea3200f1298f1c3d2b3 Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Fri, 17 Feb 2023 21:55:42 -0300 Subject: [PATCH 041/133] Delete no longer needed .gitattributes file --- .gitattributes | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 52031de51..000000000 --- a/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -*.sol linguist-language=Solidity From 815bfbf38395e0c836d09745ba69ae52844e3d8c Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Tue, 21 Feb 2023 15:18:50 +0100 Subject: [PATCH 042/133] Deprecate the timers library (#4062) Co-authored-by: Francisco --- CHANGELOG.md | 1 + contracts/utils/Timers.sol | 2 ++ 2 files changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ccd279d53..8ad77fe68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ ### Deprecations - `ERC20Permit`: Added the file `IERC20Permit.sol` and `ERC20Permit.sol` and deprecated `draft-IERC20Permit.sol` and `draft-ERC20Permit.sol` since [EIP-2612](https://eips.ethereum.org/EIPS/eip-2612) is no longer a Draft. Developers are encouraged to update their imports. ([#3793](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3793)) +- `Timers`: The `Timers` library is now deprecated and will be removed in the next major release. ([#4062](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4062)) ## 4.8.1 (2023-01-12) diff --git a/contracts/utils/Timers.sol b/contracts/utils/Timers.sol index 4bc86f202..1c92b029b 100644 --- a/contracts/utils/Timers.sol +++ b/contracts/utils/Timers.sol @@ -5,6 +5,8 @@ pragma solidity ^0.8.0; /** * @dev Tooling for timepoints, timers and delays + * + * CAUTION: This file is deprecated as of 4.9 and will be removed in the next major release. */ library Timers { struct Timestamp { From 1e245aa54bd4bd0cccdb63524b45010ce043f114 Mon Sep 17 00:00:00 2001 From: Yamen Merhi Date: Tue, 21 Feb 2023 17:16:44 +0200 Subject: [PATCH 043/133] Add `isValidERC1271SignatureNow` to SignatureChecker library (#3932) Co-authored-by: Hadrien Croubois Co-authored-by: Francisco --- .changeset/slimy-knives-hug.md | 5 ++ .../utils/cryptography/SignatureChecker.sol | 19 ++++- .../cryptography/SignatureChecker.test.js | 76 ++++++++++--------- 3 files changed, 61 insertions(+), 39 deletions(-) create mode 100644 .changeset/slimy-knives-hug.md diff --git a/.changeset/slimy-knives-hug.md b/.changeset/slimy-knives-hug.md new file mode 100644 index 000000000..94099eea7 --- /dev/null +++ b/.changeset/slimy-knives-hug.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': minor +--- + +`SignatureChecker`: Add `isValidERC1271SignatureNow` for checking a signature directly against a smart contract using ERC-1271. diff --git a/contracts/utils/cryptography/SignatureChecker.sol b/contracts/utils/cryptography/SignatureChecker.sol index e06778deb..c3a724dd0 100644 --- a/contracts/utils/cryptography/SignatureChecker.sol +++ b/contracts/utils/cryptography/SignatureChecker.sol @@ -23,10 +23,23 @@ library SignatureChecker { */ function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) { (address recovered, ECDSA.RecoverError error) = ECDSA.tryRecover(hash, signature); - if (error == ECDSA.RecoverError.NoError && recovered == signer) { - return true; - } + return + (error == ECDSA.RecoverError.NoError && recovered == signer) || + isValidERC1271SignatureNow(signer, hash, signature); + } + /** + * @dev Checks if a signature is valid for a given signer and data hash. The signature is validated + * against the signer smart contract using ERC1271. + * + * NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus + * change through time. It could return true at block N and false at block N+1 (or the opposite). + */ + function isValidERC1271SignatureNow( + address signer, + bytes32 hash, + bytes memory signature + ) internal view returns (bool) { (bool success, bytes memory result) = signer.staticcall( abi.encodeWithSelector(IERC1271.isValidSignature.selector, hash, signature) ); diff --git a/test/utils/cryptography/SignatureChecker.test.js b/test/utils/cryptography/SignatureChecker.test.js index 11054c3e1..ba8b100d1 100644 --- a/test/utils/cryptography/SignatureChecker.test.js +++ b/test/utils/cryptography/SignatureChecker.test.js @@ -40,44 +40,48 @@ contract('SignatureChecker (ERC1271)', function (accounts) { }); context('ERC1271 wallet', function () { - it('with matching signer and signature', async function () { - expect( - await this.signaturechecker.$isValidSignatureNow( - this.wallet.address, - toEthSignedMessageHash(TEST_MESSAGE), - this.signature, - ), - ).to.equal(true); - }); + for (const signature of ['isValidERC1271SignatureNow', 'isValidSignatureNow']) { + context(signature, function () { + it('with matching signer and signature', async function () { + expect( + await this.signaturechecker[`$${signature}`]( + this.wallet.address, + toEthSignedMessageHash(TEST_MESSAGE), + this.signature, + ), + ).to.equal(true); + }); - it('with invalid signer', async function () { - expect( - await this.signaturechecker.$isValidSignatureNow( - this.signaturechecker.address, - toEthSignedMessageHash(TEST_MESSAGE), - this.signature, - ), - ).to.equal(false); - }); + it('with invalid signer', async function () { + expect( + await this.signaturechecker[`$${signature}`]( + this.signaturechecker.address, + toEthSignedMessageHash(TEST_MESSAGE), + this.signature, + ), + ).to.equal(false); + }); - it('with invalid signature', async function () { - expect( - await this.signaturechecker.$isValidSignatureNow( - this.wallet.address, - toEthSignedMessageHash(WRONG_MESSAGE), - this.signature, - ), - ).to.equal(false); - }); + it('with invalid signature', async function () { + expect( + await this.signaturechecker[`$${signature}`]( + this.wallet.address, + toEthSignedMessageHash(WRONG_MESSAGE), + this.signature, + ), + ).to.equal(false); + }); - it('with malicious wallet', async function () { - expect( - await this.signaturechecker.$isValidSignatureNow( - this.malicious.address, - toEthSignedMessageHash(TEST_MESSAGE), - this.signature, - ), - ).to.equal(false); - }); + it('with malicious wallet', async function () { + expect( + await this.signaturechecker[`$${signature}`]( + this.malicious.address, + toEthSignedMessageHash(TEST_MESSAGE), + this.signature, + ), + ).to.equal(false); + }); + }); + } }); }); From df814dd374519a9388a617f500019d61bc239382 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 21 Feb 2023 19:26:14 -0300 Subject: [PATCH 044/133] Update crytic/slither-action action to v0.3.0 (#4064) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/checks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 8bb32dcc3..c37bf935b 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -82,7 +82,7 @@ jobs: - name: Set up environment uses: ./.github/actions/setup - run: rm foundry.toml - - uses: crytic/slither-action@v0.2.0 + - uses: crytic/slither-action@v0.3.0 codespell: if: github.repository != 'OpenZeppelin/openzeppelin-contracts-upgradeable' From 227473e88ce756afe41193b7d2407fdc01d7e784 Mon Sep 17 00:00:00 2001 From: Pascal Marco Caversaccio Date: Tue, 21 Feb 2023 23:27:34 +0100 Subject: [PATCH 045/133] Fix comment in `ERC4626` on decimals default (#4060) Co-authored-by: Hadrien Croubois --- contracts/token/ERC20/extensions/ERC4626.sol | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/contracts/token/ERC20/extensions/ERC4626.sol b/contracts/token/ERC20/extensions/ERC4626.sol index 16656bd4f..3846cbbbb 100644 --- a/contracts/token/ERC20/extensions/ERC4626.sol +++ b/contracts/token/ERC20/extensions/ERC4626.sol @@ -79,9 +79,10 @@ abstract contract ERC4626 is ERC20, IERC4626 { } /** - * @dev Decimals are read from the underlying asset in the constructor and cached. If this fails (e.g., the asset - * has not been created yet), the cached value is set to a default obtained by `super.decimals()` (which depends on - * inheritance but is most likely 18). Override this function in order to set a guaranteed hardcoded value. + * @dev Decimals are computed by adding the decimal offset on top of the underlying asset's decimals. This + * "original" value is cached during construction of the vault contract. If this read operation fails (e.g., the + * asset has not been created yet), a default of 18 is used to represent the underlying asset's decimals. + * * See {IERC20Metadata-decimals}. */ function decimals() public view virtual override(IERC20Metadata, ERC20) returns (uint8) { @@ -194,9 +195,6 @@ abstract contract ERC4626 is ERC20, IERC4626 { /** * @dev Internal conversion function (from assets to shares) with support for rounding direction. - * - * Will revert if assets > 0, totalSupply > 0 and totalAssets = 0. That corresponds to a case where any asset - * would represent an infinite amount of shares. */ function _convertToShares(uint256 assets, Math.Rounding rounding) internal view virtual returns (uint256) { return assets.mulDiv(totalSupply() + 10 ** _decimalsOffset(), totalAssets() + 1, rounding); @@ -213,7 +211,7 @@ abstract contract ERC4626 is ERC20, IERC4626 { * @dev Deposit/mint common workflow. */ function _deposit(address caller, address receiver, uint256 assets, uint256 shares) internal virtual { - // If _asset is ERC777, `transferFrom` can trigger a reenterancy BEFORE the transfer happens through the + // If _asset is ERC777, `transferFrom` can trigger a reentrancy BEFORE the transfer happens through the // `tokensToSend` hook. On the other hand, the `tokenReceived` hook, that is triggered after the transfer, // calls the vault, which is assumed not malicious. // From adb861fb3bb4b4167f10307b8d091326115502f9 Mon Sep 17 00:00:00 2001 From: Francisco Date: Wed, 22 Feb 2023 06:00:41 -0300 Subject: [PATCH 046/133] Change Governor.cancel to receive all parameters (#4056) --- contracts/governance/Governor.sol | 20 +++-- contracts/governance/IGovernor.sol | 11 ++- .../GovernorCompatibilityBravo.sol | 77 +++++++++++++++---- .../GovernorCompatibilityBravoMock.sol | 9 ++- contracts/mocks/wizard/MyGovernor3.sol | 9 ++- test/helpers/governance.js | 8 +- 6 files changed, 99 insertions(+), 35 deletions(-) diff --git a/contracts/governance/Governor.sol b/contracts/governance/Governor.sol index e3691a3ed..1483da6d2 100644 --- a/contracts/governance/Governor.sol +++ b/contracts/governance/Governor.sol @@ -336,10 +336,16 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor, IERC721Receive /** * @dev See {IGovernor-cancel}. */ - function cancel(uint256 proposalId) public virtual override { + function cancel( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) public virtual override returns (uint256) { + uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash); require(state(proposalId) == ProposalState.Pending, "Governor: too late to cancel"); require(_msgSender() == _proposals[proposalId].proposer, "Governor: only proposer can cancel"); - _cancel(proposalId); + return _cancel(targets, values, calldatas, descriptionHash); } /** @@ -407,16 +413,8 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor, IERC721Receive bytes[] memory calldatas, bytes32 descriptionHash ) internal virtual returns (uint256) { - return _cancel(hashProposal(targets, values, calldatas, descriptionHash)); - } + uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash); - /** - * @dev Internal cancel mechanism: locks up the proposal timer, preventing it from being re-submitted. Marks it as - * canceled to allow distinguishing it from executed proposals. - * - * Emits a {IGovernor-ProposalCanceled} event. - */ - function _cancel(uint256 proposalId) internal virtual returns (uint256) { ProposalState status = state(proposalId); require( diff --git a/contracts/governance/IGovernor.sol b/contracts/governance/IGovernor.sol index b12d2f632..70f81efe8 100644 --- a/contracts/governance/IGovernor.sol +++ b/contracts/governance/IGovernor.sol @@ -235,12 +235,17 @@ abstract contract IGovernor is IERC165, IERC6372 { ) public payable virtual returns (uint256 proposalId); /** - * @dev Cancel a proposal. This is restricted to Pending proposal (before the vote starts) and is restricted to - * the proposal's proposer. + * @dev Cancel a proposal. A proposal is cancellable by the proposer, but only while it is Pending state, i.e. + * before the vote starts. * * Emits a {ProposalCanceled} event. */ - function cancel(uint256 proposalId) public virtual; + function cancel( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) public virtual returns (uint256 proposalId); /** * @dev Cast a vote diff --git a/contracts/governance/compatibility/GovernorCompatibilityBravo.sol b/contracts/governance/compatibility/GovernorCompatibilityBravo.sol index 1b8c09368..39c895bf0 100644 --- a/contracts/governance/compatibility/GovernorCompatibilityBravo.sol +++ b/contracts/governance/compatibility/GovernorCompatibilityBravo.sol @@ -77,29 +77,55 @@ abstract contract GovernorCompatibilityBravo is IGovernorTimelock, IGovernorComp * @dev See {IGovernorCompatibilityBravo-queue}. */ function queue(uint256 proposalId) public virtual override { - ProposalDetails storage details = _proposalDetails[proposalId]; - queue( - details.targets, - details.values, - _encodeCalldata(details.signatures, details.calldatas), - details.descriptionHash - ); + ( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) = _getProposalParameters(proposalId); + + queue(targets, values, calldatas, descriptionHash); } /** * @dev See {IGovernorCompatibilityBravo-execute}. */ function execute(uint256 proposalId) public payable virtual override { - ProposalDetails storage details = _proposalDetails[proposalId]; - execute( - details.targets, - details.values, - _encodeCalldata(details.signatures, details.calldatas), - details.descriptionHash - ); + ( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) = _getProposalParameters(proposalId); + + execute(targets, values, calldatas, descriptionHash); } - function cancel(uint256 proposalId) public virtual override(IGovernor, Governor) { + /** + * @dev Cancel a proposal with GovernorBravo logic. + */ + function cancel(uint256 proposalId) public virtual { + ( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) = _getProposalParameters(proposalId); + + cancel(targets, values, calldatas, descriptionHash); + } + + /** + * @dev Cancel a proposal with GovernorBravo logic. At any moment a proposal can be cancelled, either by the + * proposer, or by third parties if the proposer's voting power has dropped below the proposal threshold. + */ + function cancel( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) public virtual override(IGovernor, Governor) returns (uint256) { + uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash); address proposer = _proposalDetails[proposalId].proposer; require( @@ -107,7 +133,7 @@ abstract contract GovernorCompatibilityBravo is IGovernorTimelock, IGovernorComp "GovernorBravo: proposer above threshold" ); - _cancel(proposalId); + return _cancel(targets, values, calldatas, descriptionHash); } /** @@ -128,6 +154,25 @@ abstract contract GovernorCompatibilityBravo is IGovernorTimelock, IGovernorComp return fullcalldatas; } + /** + * @dev Retrieve proposal parameters by id, with fully encoded calldatas. + */ + function _getProposalParameters( + uint256 proposalId + ) + private + view + returns (address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash) + { + ProposalDetails storage details = _proposalDetails[proposalId]; + return ( + details.targets, + details.values, + _encodeCalldata(details.signatures, details.calldatas), + details.descriptionHash + ); + } + /** * @dev Store proposal metadata for later lookup */ diff --git a/contracts/mocks/governance/GovernorCompatibilityBravoMock.sol b/contracts/mocks/governance/GovernorCompatibilityBravoMock.sol index 2727794f6..1b87d1433 100644 --- a/contracts/mocks/governance/GovernorCompatibilityBravoMock.sol +++ b/contracts/mocks/governance/GovernorCompatibilityBravoMock.sol @@ -66,8 +66,13 @@ abstract contract GovernorCompatibilityBravoMock is return super.execute(targets, values, calldatas, salt); } - function cancel(uint256 proposalId) public override(Governor, GovernorCompatibilityBravo, IGovernor) { - super.cancel(proposalId); + function cancel( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) public override(Governor, GovernorCompatibilityBravo, IGovernor) returns (uint256) { + return super.cancel(targets, values, calldatas, descriptionHash); } function _execute( diff --git a/contracts/mocks/wizard/MyGovernor3.sol b/contracts/mocks/wizard/MyGovernor3.sol index 4192cae94..f4d295156 100644 --- a/contracts/mocks/wizard/MyGovernor3.sol +++ b/contracts/mocks/wizard/MyGovernor3.sol @@ -54,8 +54,13 @@ contract MyGovernor is return super.propose(targets, values, calldatas, description); } - function cancel(uint256 proposalId) public override(Governor, GovernorCompatibilityBravo, IGovernor) { - super.cancel(proposalId); + function cancel( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) public override(Governor, GovernorCompatibilityBravo, IGovernor) returns (uint256) { + return super.cancel(targets, values, calldatas, descriptionHash); } function _execute( diff --git a/test/helpers/governance.js b/test/helpers/governance.js index 1ffa086cb..4b38b7588 100644 --- a/test/helpers/governance.js +++ b/test/helpers/governance.js @@ -68,7 +68,13 @@ class GovernorHelper { switch (visibility) { case 'external': - return this.governor.methods['cancel(uint256)'](...concatOpts([proposal.id], opts)); + if (proposal.useCompatibilityInterface) { + return this.governor.methods['cancel(uint256)'](...concatOpts([proposal.id], opts)); + } else { + return this.governor.methods['cancel(address[],uint256[],bytes[],bytes32)']( + ...concatOpts(proposal.shortProposal, opts), + ); + } case 'internal': return this.governor.methods['$_cancel(address[],uint256[],bytes[],bytes32)']( ...concatOpts(proposal.shortProposal, opts), From 53235263a377612b546a5c1922e1876689eba525 Mon Sep 17 00:00:00 2001 From: Yamen Merhi Date: Wed, 22 Feb 2023 16:22:50 +0200 Subject: [PATCH 047/133] Implement `0x00` version of EIP-191 in ECDSA Library (#4063) --- .changeset/small-cars-appear.md | 5 +++++ contracts/utils/cryptography/ECDSA.sol | 10 ++++++++++ test/helpers/sign.js | 16 ++++++++++++++++ test/utils/cryptography/ECDSA.test.js | 11 ++++++++++- 4 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 .changeset/small-cars-appear.md diff --git a/.changeset/small-cars-appear.md b/.changeset/small-cars-appear.md new file mode 100644 index 000000000..0263bcd18 --- /dev/null +++ b/.changeset/small-cars-appear.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': patch +--- + +`ECDSA`: Add a function `toDataWithIntendedValidatorHash` that encodes data with version 0x00 following EIP-191. diff --git a/contracts/utils/cryptography/ECDSA.sol b/contracts/utils/cryptography/ECDSA.sol index a499b546b..77279eb4f 100644 --- a/contracts/utils/cryptography/ECDSA.sol +++ b/contracts/utils/cryptography/ECDSA.sol @@ -204,4 +204,14 @@ library ECDSA { data := keccak256(ptr, 0x42) } } + + /** + * @dev Returns an Ethereum Signed Data with intended validator, created from a + * `validator` and `data` according to the version 0 of EIP-191. + * + * See {recover}. + */ + function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { + return keccak256(abi.encodePacked("\x19\x00", validator, data)); + } } diff --git a/test/helpers/sign.js b/test/helpers/sign.js index 417ef591d..d537116bb 100644 --- a/test/helpers/sign.js +++ b/test/helpers/sign.js @@ -4,6 +4,21 @@ function toEthSignedMessageHash(messageHex) { return web3.utils.sha3(Buffer.concat([prefix, messageBuffer])); } +/** + * Create a signed data with intended validator according to the version 0 of EIP-191 + * @param validatorAddress The address of the validator + * @param dataHex The data to be concatenated with the prefix and signed + */ +function toDataWithIntendedValidatorHash(validatorAddress, dataHex) { + const validatorBuffer = Buffer.from(web3.utils.hexToBytes(validatorAddress)); + const dataBuffer = Buffer.from(web3.utils.hexToBytes(dataHex)); + const preambleBuffer = Buffer.from('\x19'); + const versionBuffer = Buffer.from('\x00'); + const ethMessage = Buffer.concat([preambleBuffer, versionBuffer, validatorBuffer, dataBuffer]); + + return web3.utils.sha3(ethMessage); +} + /** * Create a signer between a contract and a signer for a voucher of method, args, and redeemer * Note that `method` is the web3 method, not the truffle-contract method @@ -43,5 +58,6 @@ const getSignFor = module.exports = { toEthSignedMessageHash, + toDataWithIntendedValidatorHash, getSignFor, }; diff --git a/test/utils/cryptography/ECDSA.test.js b/test/utils/cryptography/ECDSA.test.js index 3b19cde60..ae737086b 100644 --- a/test/utils/cryptography/ECDSA.test.js +++ b/test/utils/cryptography/ECDSA.test.js @@ -1,5 +1,5 @@ const { expectRevert } = require('@openzeppelin/test-helpers'); -const { toEthSignedMessageHash } = require('../../helpers/sign'); +const { toEthSignedMessageHash, toDataWithIntendedValidatorHash } = require('../../helpers/sign'); const { expect } = require('chai'); @@ -8,6 +8,7 @@ const ECDSA = artifacts.require('$ECDSA'); const TEST_MESSAGE = web3.utils.sha3('OpenZeppelin'); const WRONG_MESSAGE = web3.utils.sha3('Nope'); const NON_HASH_MESSAGE = '0x' + Buffer.from('abcd').toString('hex'); +const RANDOM_ADDRESS = web3.utils.toChecksumAddress(web3.utils.randomHex(20)); function to2098Format(signature) { const long = web3.utils.hexToBytes(signature); @@ -248,4 +249,12 @@ contract('ECDSA', function (accounts) { ); }); }); + + context('toDataWithIntendedValidatorHash', function () { + it('returns the hash correctly', async function () { + expect( + await this.ecdsa.methods['$toDataWithIntendedValidatorHash(address,bytes)'](RANDOM_ADDRESS, NON_HASH_MESSAGE), + ).to.equal(toDataWithIntendedValidatorHash(RANDOM_ADDRESS, NON_HASH_MESSAGE)); + }); + }); }); From 7b3e7b7055d6e1226d4920ca7d7c446c0c0bfff5 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Wed, 22 Feb 2023 19:23:06 +0100 Subject: [PATCH 048/133] Re-enable ERC4626 property test on empty vaults (#4068) --- test/token/ERC20/extensions/ERC4626.t.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/token/ERC20/extensions/ERC4626.t.sol b/test/token/ERC20/extensions/ERC4626.t.sol index 03786b271..95514531c 100644 --- a/test/token/ERC20/extensions/ERC4626.t.sol +++ b/test/token/ERC20/extensions/ERC4626.t.sol @@ -12,7 +12,7 @@ contract ERC4626StdTest is ERC4626Test { _underlying_ = address(new ERC20Mock()); _vault_ = address(new ERC4626Mock(_underlying_)); _delta_ = 0; - _vaultMayBeEmpty = false; + _vaultMayBeEmpty = true; _unlimitedAmount = true; } } From 9d06a1b64bcff51349d832222c165b03f9c1f316 Mon Sep 17 00:00:00 2001 From: Francisco Date: Thu, 23 Feb 2023 08:52:10 -0300 Subject: [PATCH 049/133] Remove unused Solhint overrides (#4069) --- contracts/utils/cryptography/EIP712.sol | 3 --- 1 file changed, 3 deletions(-) diff --git a/contracts/utils/cryptography/EIP712.sol b/contracts/utils/cryptography/EIP712.sol index d0e52c396..e06d0066b 100644 --- a/contracts/utils/cryptography/EIP712.sol +++ b/contracts/utils/cryptography/EIP712.sol @@ -38,7 +38,6 @@ abstract contract EIP712 is IERC5267 { bytes32 private constant _TYPE_HASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); - /* solhint-disable var-name-mixedcase */ // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to // invalidate the cached domain separator if the chain id changes. bytes32 private immutable _cachedDomainSeparator; @@ -53,8 +52,6 @@ abstract contract EIP712 is IERC5267 { bytes32 private immutable _hashedName; bytes32 private immutable _hashedVersion; - /* solhint-enable var-name-mixedcase */ - /** * @dev Initializes the domain separator and parameter caches. * From a6b8366980d8b28cbe4be7f1798719f0fac4cac1 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Thu, 23 Feb 2023 21:06:47 +0100 Subject: [PATCH 050/133] Improve ERC4626 event coverage (#4072) --- test/token/ERC20/extensions/ERC4626.test.js | 106 +++++++++++++++++++- 1 file changed, 101 insertions(+), 5 deletions(-) diff --git a/test/token/ERC20/extensions/ERC4626.test.js b/test/token/ERC20/extensions/ERC4626.test.js index 0c67a2fc7..2f7b99d38 100644 --- a/test/token/ERC20/extensions/ERC4626.test.js +++ b/test/token/ERC20/extensions/ERC4626.test.js @@ -66,6 +66,13 @@ contract('ERC4626', function (accounts) { to: recipient, value: parseShare(1), }); + + await expectEvent.inTransaction(tx, this.vault, 'Deposit', { + sender: holder, + owner: recipient, + assets: parseToken(1), + shares: parseShare(1), + }); }); it('mint', async function () { @@ -85,6 +92,13 @@ contract('ERC4626', function (accounts) { to: recipient, value: parseShare(1), }); + + await expectEvent.inTransaction(tx, this.vault, 'Deposit', { + sender: holder, + owner: recipient, + assets: parseToken(1), + shares: parseShare(1), + }); }); it('withdraw', async function () { @@ -104,6 +118,14 @@ contract('ERC4626', function (accounts) { to: constants.ZERO_ADDRESS, value: '0', }); + + await expectEvent.inTransaction(tx, this.vault, 'Withdraw', { + sender: holder, + receiver: recipient, + owner: holder, + assets: '0', + shares: '0', + }); }); it('redeem', async function () { @@ -123,6 +145,14 @@ contract('ERC4626', function (accounts) { to: constants.ZERO_ADDRESS, value: '0', }); + + await expectEvent.inTransaction(tx, this.vault, 'Withdraw', { + sender: holder, + receiver: recipient, + owner: holder, + assets: '0', + shares: '0', + }); }); }); @@ -171,6 +201,13 @@ contract('ERC4626', function (accounts) { to: recipient, value: expectedShares, }); + + await expectEvent.inTransaction(tx, this.vault, 'Deposit', { + sender: holder, + owner: recipient, + assets: depositAssets, + shares: expectedShares, + }); }); /** @@ -207,6 +244,13 @@ contract('ERC4626', function (accounts) { to: recipient, value: mintShares, }); + + await expectEvent.inTransaction(tx, this.vault, 'Deposit', { + sender: holder, + owner: recipient, + assets: expectedAssets, + shares: mintShares, + }); }); it('withdraw', async function () { @@ -226,6 +270,14 @@ contract('ERC4626', function (accounts) { to: constants.ZERO_ADDRESS, value: '0', }); + + await expectEvent.inTransaction(tx, this.vault, 'Withdraw', { + sender: holder, + receiver: recipient, + owner: holder, + assets: '0', + shares: '0', + }); }); it('redeem', async function () { @@ -245,6 +297,14 @@ contract('ERC4626', function (accounts) { to: constants.ZERO_ADDRESS, value: '0', }); + + await expectEvent.inTransaction(tx, this.vault, 'Withdraw', { + sender: holder, + receiver: recipient, + owner: holder, + assets: '0', + shares: '0', + }); }); }); @@ -292,6 +352,13 @@ contract('ERC4626', function (accounts) { to: recipient, value: expectedShares, }); + + await expectEvent.inTransaction(tx, this.vault, 'Deposit', { + sender: holder, + owner: recipient, + assets: depositAssets, + shares: expectedShares, + }); }); /** @@ -326,6 +393,13 @@ contract('ERC4626', function (accounts) { to: recipient, value: mintShares, }); + + await expectEvent.inTransaction(tx, this.vault, 'Deposit', { + sender: holder, + owner: recipient, + assets: expectedAssets, + shares: mintShares, + }); }); it('withdraw', async function () { @@ -351,6 +425,14 @@ contract('ERC4626', function (accounts) { to: constants.ZERO_ADDRESS, value: expectedShares, }); + + await expectEvent.inTransaction(tx, this.vault, 'Withdraw', { + sender: holder, + receiver: recipient, + owner: holder, + assets: withdrawAssets, + shares: expectedShares, + }); }); it('withdraw with approval', async function () { @@ -363,21 +445,35 @@ contract('ERC4626', function (accounts) { }); it('redeem', async function () { - expect(await this.vault.maxRedeem(holder)).to.be.bignumber.equal(parseShare(100)); - expect(await this.vault.previewRedeem(parseShare(100))).to.be.bignumber.equal(parseToken(1)); + const effectiveAssets = await this.vault.totalAssets().then(x => x.add(virtualAssets)); + const effectiveShares = await this.vault.totalSupply().then(x => x.add(virtualShares)); - const { tx } = await this.vault.redeem(parseShare(100), recipient, holder, { from: holder }); + const redeemShares = parseShare(100); + const expectedAssets = redeemShares.mul(effectiveAssets).div(effectiveShares); + + expect(await this.vault.maxRedeem(holder)).to.be.bignumber.equal(redeemShares); + expect(await this.vault.previewRedeem(redeemShares)).to.be.bignumber.equal(expectedAssets); + + const { tx } = await this.vault.redeem(redeemShares, recipient, holder, { from: holder }); await expectEvent.inTransaction(tx, this.token, 'Transfer', { from: this.vault.address, to: recipient, - value: parseToken(1), + value: expectedAssets, }); await expectEvent.inTransaction(tx, this.vault, 'Transfer', { from: holder, to: constants.ZERO_ADDRESS, - value: parseShare(100), + value: redeemShares, + }); + + await expectEvent.inTransaction(tx, this.vault, 'Withdraw', { + sender: holder, + receiver: recipient, + owner: holder, + assets: expectedAssets, + shares: redeemShares, }); }); From 6e88df28cb45712790c02b7aef7a866a3b9c5512 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Fri, 24 Feb 2023 00:06:22 +0100 Subject: [PATCH 051/133] Mark ERC777 and ERC1820 as deprecated (#4066) --- CHANGELOG.md | 2 ++ contracts/token/ERC777/ERC777.sol | 2 ++ contracts/token/ERC777/README.adoc | 2 ++ contracts/utils/introspection/ERC1820Implementer.sol | 2 ++ docs/modules/ROOT/pages/erc777.adoc | 2 ++ 5 files changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ad77fe68..e882fd516 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ - `ERC20Permit`: Added the file `IERC20Permit.sol` and `ERC20Permit.sol` and deprecated `draft-IERC20Permit.sol` and `draft-ERC20Permit.sol` since [EIP-2612](https://eips.ethereum.org/EIPS/eip-2612) is no longer a Draft. Developers are encouraged to update their imports. ([#3793](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3793)) - `Timers`: The `Timers` library is now deprecated and will be removed in the next major release. ([#4062](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4062)) +- `ERC777`: The `ERC777` token standard is no longer supported by OpenZeppelin. Our implementation is now deprecated and will be removed in the next major release. The corresponding standard interfaces remain available. ([#4066](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4066)) +- `ERC1820Implementer`: The `ERC1820` pseudo-introspection mechanism is no longer supported by OpenZeppelin. Our implementation is now deprecated and will be removed in the next major release. The corresponding standard interfaces remain available. ([#4066](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4066)) ## 4.8.1 (2023-01-12) diff --git a/contracts/token/ERC777/ERC777.sol b/contracts/token/ERC777/ERC777.sol index c1503c4df..0e5af5d08 100644 --- a/contracts/token/ERC777/ERC777.sol +++ b/contracts/token/ERC777/ERC777.sol @@ -25,6 +25,8 @@ import "../../utils/introspection/IERC1820Registry.sol"; * Additionally, the {IERC777-granularity} value is hard-coded to `1`, meaning that there * are no special restrictions in the amount of tokens that created, moved, or * destroyed. This makes integration with ERC20 applications seamless. + * + * CAUTION: This file is deprecated as of v4.9 and will be removed in the next major release. */ contract ERC777 is Context, IERC777, IERC20 { using Address for address; diff --git a/contracts/token/ERC777/README.adoc b/contracts/token/ERC777/README.adoc index 5012a3110..ac326abe6 100644 --- a/contracts/token/ERC777/README.adoc +++ b/contracts/token/ERC777/README.adoc @@ -3,6 +3,8 @@ [.readme-notice] NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/token/erc777 +CAUTION: As of v4.9, OpenZeppelin's implementation of ERC-777 is deprecated and will be removed in the next major release. + This set of interfaces and contracts are all related to the https://eips.ethereum.org/EIPS/eip-777[ERC777 token standard]. TIP: For an overview of ERC777 tokens and a walk through on how to create a token contract read our xref:ROOT:erc777.adoc[ERC777 guide]. diff --git a/contracts/utils/introspection/ERC1820Implementer.sol b/contracts/utils/introspection/ERC1820Implementer.sol index ac5a884c0..cf4b50498 100644 --- a/contracts/utils/introspection/ERC1820Implementer.sol +++ b/contracts/utils/introspection/ERC1820Implementer.sol @@ -12,6 +12,8 @@ import "./IERC1820Implementer.sol"; * declare their willingness to be implementers. * {IERC1820Registry-setInterfaceImplementer} should then be called for the * registration to be complete. + * + * CAUTION: This file is deprecated as of v4.9 and will be removed in the next major release. */ contract ERC1820Implementer is IERC1820Implementer { bytes32 private constant _ERC1820_ACCEPT_MAGIC = keccak256("ERC1820_ACCEPT_MAGIC"); diff --git a/docs/modules/ROOT/pages/erc777.adoc b/docs/modules/ROOT/pages/erc777.adoc index d79fbee28..4a0af16c3 100644 --- a/docs/modules/ROOT/pages/erc777.adoc +++ b/docs/modules/ROOT/pages/erc777.adoc @@ -1,5 +1,7 @@ = ERC777 +CAUTION: As of v4.9, OpenZeppelin's implementation of ERC-777 is deprecated and will be removed in the next major release. + Like xref:erc20.adoc[ERC20], ERC777 is a standard for xref:tokens.adoc#different-kinds-of-tokens[_fungible_ tokens], and is focused around allowing more complex interactions when trading tokens. More generally, it brings tokens and Ether closer together by providing the equivalent of a `msg.value` field, but for tokens. The standard also brings multiple quality-of-life improvements, such as getting rid of the confusion around `decimals`, minting and burning with proper events, among others, but its killer feature is *receive hooks*. A hook is simply a function in a contract that is called when tokens are sent to it, meaning *accounts and contracts can react to receiving tokens*. From 62dbb1b06a5e86ef72fb9e0716d37fd20dbe522d Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Fri, 24 Feb 2023 15:48:30 +0100 Subject: [PATCH 052/133] Document clock modes for token and governor (#4058) Co-authored-by: Francisco --- contracts/interfaces/README.adoc | 13 ++- docs/modules/ROOT/pages/governance.adoc | 121 ++++++++++++++++++++++-- 2 files changed, 125 insertions(+), 9 deletions(-) diff --git a/contracts/interfaces/README.adoc b/contracts/interfaces/README.adoc index 5b4cedf95..8748da8a4 100644 --- a/contracts/interfaces/README.adoc +++ b/contracts/interfaces/README.adoc @@ -30,6 +30,11 @@ are useful to interact with third party contracts that implement them. - {IERC3156FlashLender} - {IERC3156FlashBorrower} - {IERC4626} +- {IERC4906} +- {IERC5267} +- {IERC5313} +- {IERC5805} +- {IERC6372} == Detailed ABI @@ -53,4 +58,10 @@ are useful to interact with third party contracts that implement them. {{IERC3156FlashBorrower}} -{{IERC4626}} \ No newline at end of file +{{IERC4626}} + +{{IERC5267}} + +{{IERC5805}} + +{{IERC6372}} diff --git a/docs/modules/ROOT/pages/governance.adoc b/docs/modules/ROOT/pages/governance.adoc index eb76321bf..cd7dd4e6f 100644 --- a/docs/modules/ROOT/pages/governance.adoc +++ b/docs/modules/ROOT/pages/governance.adoc @@ -119,13 +119,15 @@ contract MyToken is ERC20, ERC20Permit, ERC20Votes, ERC20Wrapper { } ``` -NOTE:The only other source of voting power available in OpenZeppelin Contracts currently is xref:api:token/ERC721.adoc#ERC721Votes[`ERC721Votes`]. ERC721 tokens that don't provide this functionality can be wrapped into a voting tokens using a combination of xref:api:token/ERC721.adoc#ERC721Votes[`ERC721Votes`] and xref:api:token/ERC721Wrapper.adoc#ERC721Wrapper[`ERC721Wrapper`]. +NOTE: The only other source of voting power available in OpenZeppelin Contracts currently is xref:api:token/ERC721.adoc#ERC721Votes[`ERC721Votes`]. ERC721 tokens that don't provide this functionality can be wrapped into a voting tokens using a combination of xref:api:token/ERC721.adoc#ERC721Votes[`ERC721Votes`] and xref:api:token/ERC721Wrapper.adoc#ERC721Wrapper[`ERC721Wrapper`]. + +NOTE: The internal clock used by the token to store voting balances will dictate the operating mode of the Governor contract attached to it. By default, block numbers are used. Since v4.9, developers can override the xref:api:interfaces.adoc#IERC6372[IERC6372] clock to use timestamps instead of block numbers. === Governor Initially, we will build a Governor without a timelock. The core logic is given by the Governor contract, but we still need to choose: 1) how voting power is determined, 2) how many votes are needed for quorum, 3) what options people have when casting a vote and how those votes are counted, and 4) what type of token should be used to vote. Each of these aspects is customizable by writing your own module, or more easily choosing one from OpenZeppelin Contracts. -For 1) we will use the GovernorVotes module, which hooks to an IVotes instance to determine the voting power of an account based on the token balance they hold when a proposal becomes active. This module requires as a constructor parameter the address of the token. +For 1) we will use the GovernorVotes module, which hooks to an IVotes instance to determine the voting power of an account based on the token balance they hold when a proposal becomes active. This module requires as a constructor parameter the address of the token. This module also discovers the clock mode (ERC6372) used by the token and applies it to the Governor. For 2) we will use GovernorVotesQuorumFraction which works together with ERC20Votes to define quorum as a percentage of the total supply at the block a proposal’s voting power is retrieved. This requires a constructor parameter to set the percentage. Most Governors nowadays use 4%, so we will initialize the module with parameter 4 (this indicates the percentage, resulting in 4%). @@ -137,7 +139,7 @@ votingDelay: How long after a proposal is created should voting power be fixed. votingPeriod: How long does a proposal remain open to votes. -These parameters are specified in number of blocks. Assuming block time of around 12 seconds, we will set votingDelay = 1 day = 7200 blocks, and votingPeriod = 1 week = 50400 blocks. +These parameters are specified in the unit defined in the token's clock. Assuming the token uses block numbers, and assuming block time of around 12 seconds, we will have set votingDelay = 1 day = 7200 blocks, and votingPeriod = 1 week = 50400 blocks. We can optionally set a proposal threshold as well. This restricts proposal creation to accounts who have enough voting power. @@ -160,11 +162,11 @@ contract MyGovernor is Governor, GovernorCompatibilityBravo, GovernorVotes, Gove {} function votingDelay() public pure override returns (uint256) { - return 6575; // 1 day + return 7200; // 1 day } function votingPeriod() public pure override returns (uint256) { - return 46027; // 1 week + return 50400; // 1 week } function proposalThreshold() public pure override returns (uint256) { @@ -223,7 +225,6 @@ contract MyGovernor is Governor, GovernorCompatibilityBravo, GovernorVotes, Gove return super.supportsInterface(interfaceId); } } - ``` === Timelock @@ -261,7 +262,7 @@ const grantAmount = ...; const transferCalldata = token.interface.encodeFunctionData(‘transfer’, [teamAddress, grantAmount]); ``` -Now we are ready to call the propose function of the governor. Note that we don’t pass in one array of actions, but instead three arrays corresponding to the list of targets, the list of values, and the list of calldatas. In this case it’s a single action, so it’s simple: +Now we are ready to call the propose function of the Governor. Note that we don’t pass in one array of actions, but instead three arrays corresponding to the list of targets, the list of values, and the list of calldatas. In this case it’s a single action, so it’s simple: ```javascript await governor.propose( @@ -305,7 +306,7 @@ await governor.queue( ); ``` -This will cause the governor to interact with the timelock contract and queue the actions for execution after the required delay. +This will cause the Governor to interact with the timelock contract and queue the actions for execution after the required delay. After enough time has passed (according to the timelock parameters), the proposal can be executed. If there was no timelock to begin with, this step can be ran immediately after the proposal succeeds. @@ -319,3 +320,107 @@ await governor.execute( ``` Executing the proposal will transfer the ERC20 tokens to the chosen recipient. To wrap up: we set up a system where a treasury is controlled by the collective decision of the token holders of a project, and all actions are executed via proposals enforced by on-chain votes. + +== Timestamp based governance + +=== Motivation + +It is sometimes difficult to deal with durations expressed in number of blocks because of inconsistent or unpredictable time between blocks. This is particularly true of some L2 networks where blocks are produced based on blockchain usage. Using number of blocks can also lead to the governance rules being affected by network upgrades that modify the expected time between blocks. + +The difficulty of replacing block numbers with timestamps is that the Governor and the token must both use the same format when querying past votes. If a token is designed around block numbers, it is not possible for a Governor to reliably do timestamp based lookups. + +Therefore, designing a timestamp based voting system starts with the token. + +=== Token + +Since v4.9, all voting contracts (including xref:api:token/ERC20.adoc#ERC20Votes[`ERC20Votes`] and xref:api:token/ERC721.adoc#ERC721Votes[`ERC721Votes`]) rely on xref:api:interfaces.adoc#IERC6372[IERC6372] for clock management. In order to change from operating with block numbers to operating with timestamps, all that is required is to override the `clock()` and `CLOCK_MODE()` functions. + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.2; + +import "github.com/openzeppelin/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; +import "github.com/openzeppelin/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Permit.sol"; +import "github.com/openzeppelin/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Votes.sol"; + +contract MyToken is ERC20, ERC20Permit, ERC20Votes { + constructor() ERC20("MyToken", "MTK") ERC20Permit("MyToken") {} + + // Overrides IERC6372 functions to make the token & governor timestamp-based + + function clock() public view override returns (uint48) { + return uint48(block.timestamp); + } + + function CLOCK_MODE() public pure override returns (string memory) { + return "mode=timestamp"; + } + + // The functions below are overrides required by Solidity. + + function _afterTokenTransfer(address from, address to, uint256 amount) + internal + override(ERC20, ERC20Votes) + { + super._afterTokenTransfer(from, to, amount); + } + + function _mint(address to, uint256 amount) + internal + override(ERC20, ERC20Votes) + { + super._mint(to, amount); + } + + function _burn(address account, uint256 amount) + internal + override(ERC20, ERC20Votes) + { + super._burn(account, amount); + } +} +``` + +=== Governor + +The Governor will automatically detect the clock mode used by the token and adapt to it. There is no need to override anything in the Governor contract. However, the clock mode does affect how some values are interpreted. It is therefore necessary to set the `votingDelay()` and `votingPeriod()` accordingly. + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.2; + +import "@openzeppelin/contracts/governance/Governor.sol"; +import "@openzeppelin/contracts/governance/compatibility/GovernorCompatibilityBravo.sol"; +import "@openzeppelin/contracts/governance/extensions/GovernorVotes.sol"; +import "@openzeppelin/contracts/governance/extensions/GovernorVotesQuorumFraction.sol"; +import "@openzeppelin/contracts/governance/extensions/GovernorTimelockControl.sol"; + +contract MyGovernor is Governor, GovernorCompatibilityBravo, GovernorVotes, GovernorVotesQuorumFraction, GovernorTimelockControl { + constructor(IVotes _token, TimelockController _timelock) + Governor("MyGovernor") + GovernorVotes(_token) + GovernorVotesQuorumFraction(4) + GovernorTimelockControl(_timelock) + {} + + function votingDelay() public pure virtual override returns (uint256) { + return 1 days; + } + + function votingPeriod() public pure virtual override returns (uint256) { + return 1 weeks; + } + + function proposalThreshold() public pure virtual override returns (uint256) { + return 0; + } + + // ... +} +``` + +=== Disclaimer + +Timestamp based voting is a recent feature that was formalized in EIP-6372 and EIP-5805, and introduced in v4.9. At the time this feature is released, governance tooling such as https://www.tally.xyz[Tally] does not support it yet. While support for timestamps should come soon, users can expect invalid reporting of deadlines & durations. This invalid reporting by offchain tools does not affect the onchain security and functionality of the governance contract. + +Governors with timestamp support (v4.9 and above) are compatible with old tokens (before v4.9) and will operate in "block number" mode (which is the mode all old tokens operate on). On the other hand, old Governor instances (before v4.9) are not compatible with new tokens operating using timestamps. If you update your token code to use timestamps, make sure to also update your Governor code. From d5581531deabf016552705eac9234a5d4c2935b1 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Fri, 24 Feb 2023 15:49:10 +0100 Subject: [PATCH 053/133] Add a "fees" section to the ERC4626 guide (#4054) Co-authored-by: Francisco Giordano --- contracts/mocks/docs/ERC4626Fees.sol | 87 ++++++++++++++ contracts/mocks/token/ERC4646FeesMock.sol | 40 ++++++ docs/modules/ROOT/pages/erc4626.adoc | 22 ++++ scripts/prepare-docs.sh | 8 ++ test/token/ERC20/extensions/ERC4626.test.js | 127 ++++++++++++++++++++ 5 files changed, 284 insertions(+) create mode 100644 contracts/mocks/docs/ERC4626Fees.sol create mode 100644 contracts/mocks/token/ERC4646FeesMock.sol diff --git a/contracts/mocks/docs/ERC4626Fees.sol b/contracts/mocks/docs/ERC4626Fees.sol new file mode 100644 index 000000000..8ff162953 --- /dev/null +++ b/contracts/mocks/docs/ERC4626Fees.sol @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../token/ERC20/extensions/ERC4626.sol"; + +abstract contract ERC4626Fees is ERC4626 { + using Math for uint256; + + /** @dev See {IERC4626-previewDeposit}. */ + function previewDeposit(uint256 assets) public view virtual override returns (uint256) { + uint256 fee = _feeOnTotal(assets, _entryFeeBasePoint()); + return super.previewDeposit(assets - fee); + } + + /** @dev See {IERC4626-previewMint}. */ + function previewMint(uint256 shares) public view virtual override returns (uint256) { + uint256 assets = super.previewMint(shares); + return assets + _feeOnRaw(assets, _entryFeeBasePoint()); + } + + /** @dev See {IERC4626-previewWithdraw}. */ + function previewWithdraw(uint256 assets) public view virtual override returns (uint256) { + uint256 fee = _feeOnRaw(assets, _exitFeeBasePoint()); + return super.previewWithdraw(assets + fee); + } + + /** @dev See {IERC4626-previewRedeem}. */ + function previewRedeem(uint256 shares) public view virtual override returns (uint256) { + uint256 assets = super.previewRedeem(shares); + return assets - _feeOnTotal(assets, _exitFeeBasePoint()); + } + + /** @dev See {IERC4626-_deposit}. */ + function _deposit(address caller, address receiver, uint256 assets, uint256 shares) internal virtual override { + uint256 fee = _feeOnTotal(assets, _entryFeeBasePoint()); + address recipient = _entryFeeRecipient(); + + super._deposit(caller, receiver, assets, shares); + + if (fee > 0 && recipient != address(this)) { + SafeERC20.safeTransfer(IERC20(asset()), recipient, fee); + } + } + + /** @dev See {IERC4626-_deposit}. */ + function _withdraw( + address caller, + address receiver, + address owner, + uint256 assets, + uint256 shares + ) internal virtual override { + uint256 fee = _feeOnRaw(assets, _exitFeeBasePoint()); + address recipient = _exitFeeRecipient(); + + super._withdraw(caller, receiver, owner, assets, shares); + + if (fee > 0 && recipient != address(this)) { + SafeERC20.safeTransfer(IERC20(asset()), recipient, fee); + } + } + + function _entryFeeBasePoint() internal view virtual returns (uint256) { + return 0; + } + + function _entryFeeRecipient() internal view virtual returns (address) { + return address(0); + } + + function _exitFeeBasePoint() internal view virtual returns (uint256) { + return 0; + } + + function _exitFeeRecipient() internal view virtual returns (address) { + return address(0); + } + + function _feeOnRaw(uint256 assets, uint256 feeBasePoint) private pure returns (uint256) { + return assets.mulDiv(feeBasePoint, 1e5, Math.Rounding.Up); + } + + function _feeOnTotal(uint256 assets, uint256 feeBasePoint) private pure returns (uint256) { + return assets.mulDiv(feeBasePoint, feeBasePoint + 1e5, Math.Rounding.Up); + } +} diff --git a/contracts/mocks/token/ERC4646FeesMock.sol b/contracts/mocks/token/ERC4646FeesMock.sol new file mode 100644 index 000000000..cd8f41012 --- /dev/null +++ b/contracts/mocks/token/ERC4646FeesMock.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../docs/ERC4626Fees.sol"; + +abstract contract ERC4626FeesMock is ERC4626Fees { + uint256 private immutable _entryFeeBasePointValue; + address private immutable _entryFeeRecipientValue; + uint256 private immutable _exitFeeBasePointValue; + address private immutable _exitFeeRecipientValue; + + constructor( + uint256 entryFeeBasePoint, + address entryFeeRecipient, + uint256 exitFeeBasePoint, + address exitFeeRecipient + ) { + _entryFeeBasePointValue = entryFeeBasePoint; + _entryFeeRecipientValue = entryFeeRecipient; + _exitFeeBasePointValue = exitFeeBasePoint; + _exitFeeRecipientValue = exitFeeRecipient; + } + + function _entryFeeBasePoint() internal view virtual override returns (uint256) { + return _entryFeeBasePointValue; + } + + function _entryFeeRecipient() internal view virtual override returns (address) { + return _entryFeeRecipientValue; + } + + function _exitFeeBasePoint() internal view virtual override returns (uint256) { + return _exitFeeBasePointValue; + } + + function _exitFeeRecipient() internal view virtual override returns (address) { + return _exitFeeRecipientValue; + } +} diff --git a/docs/modules/ROOT/pages/erc4626.adoc b/docs/modules/ROOT/pages/erc4626.adoc index 11c13ca95..00d46a4d0 100644 --- a/docs/modules/ROOT/pages/erc4626.adoc +++ b/docs/modules/ROOT/pages/erc4626.adoc @@ -191,3 +191,25 @@ stem:[\delta = 3], stem:[a_0 = 100], stem:[a_1 = 10^5] image::erc4626-attack-6.png[Inflation attack without offset=6] stem:[\delta = 6], stem:[a_0 = 1], stem:[a_1 = 10^5] + + +[[fees]] +== Custom behavior: Adding fees to the vault + +In an ERC4626 vaults, fees can be captured during the deposit/mint and/or during the withdraw/redeem steps. In both cases it is essential to remain compliant with the ERC4626 requirements with regard to the preview functions. + +For example, if calling `deposit(100, receiver)`, the caller should deposit exactly 100 underlying tokens, including fees, and the receiver should receive a number of shares that matches the value returned by `previewDeposit(100)`. Similarly, `previewMint` should account for the fees that the user will have to pay on top of share's cost. + +As for the `Deposit` event, while this is less clear in the EIP spec itself, there seems to be consensus that it should include the number of assets paid for by the user, including the fees. + +On the other hand, when withdrawing assets, the number given by the user should correspond to what he receives. Any fees should be added to the quote (in shares) performed by `previewWithdraw`. + +The `Withdraw` event should include the number of shares the user burns (including fees) and the number of assets the user actually receives (after fees are deducted). + +The consequence of this design is that both the `Deposit` and `Withdraw` events will describe two exchange rates. The spread between the "Buy-in" and the "Exit" prices correspond to the fees taken by the vault. + +The following example describes how fees proportional to the deposited/withdrawn amount can be implemented: + +```solidity +include::api:example$ERC4626Fees.sol[] +``` diff --git a/scripts/prepare-docs.sh b/scripts/prepare-docs.sh index 4fc0c957a..bb9c5d0ad 100755 --- a/scripts/prepare-docs.sh +++ b/scripts/prepare-docs.sh @@ -12,4 +12,12 @@ rm -rf "$OUTDIR" hardhat docgen +# copy examples and adjust imports +examples_dir="docs/modules/api/examples" +mkdir -p "$examples_dir" +for f in contracts/mocks/docs/*.sol; do + name="$(basename "$f")" + sed -e '/^import/s|\.\./\.\./|@openzeppelin/contracts/|' "$f" > "docs/modules/api/examples/$name" +done + node scripts/gen-nav.js "$OUTDIR" > "$OUTDIR/../nav.adoc" diff --git a/test/token/ERC20/extensions/ERC4626.test.js b/test/token/ERC20/extensions/ERC4626.test.js index 2f7b99d38..c9e5a4098 100644 --- a/test/token/ERC20/extensions/ERC4626.test.js +++ b/test/token/ERC20/extensions/ERC4626.test.js @@ -4,6 +4,7 @@ const { expect } = require('chai'); const ERC20Decimals = artifacts.require('$ERC20DecimalsMock'); const ERC4626 = artifacts.require('$ERC4626'); const ERC4626OffsetMock = artifacts.require('$ERC4626OffsetMock'); +const ERC4626FeesMock = artifacts.require('$ERC4626FeesMock'); contract('ERC4626', function (accounts) { const [holder, recipient, spender, other, user1, user2] = accounts; @@ -489,6 +490,132 @@ contract('ERC4626', function (accounts) { }); } + describe('ERC4626Fees', function () { + const feeBasePoint = web3.utils.toBN(5e3); + const amountWithoutFees = web3.utils.toBN(10000); + const fees = amountWithoutFees.mul(feeBasePoint).divn(1e5); + const amountWithFees = amountWithoutFees.add(fees); + + describe('input fees', function () { + beforeEach(async function () { + this.token = await ERC20Decimals.new(name, symbol, 18); + this.vault = await ERC4626FeesMock.new( + name + ' Vault', + symbol + 'V', + this.token.address, + feeBasePoint, + other, + 0, + constants.ZERO_ADDRESS, + ); + + await this.token.$_mint(holder, constants.MAX_INT256); + await this.token.approve(this.vault.address, constants.MAX_INT256, { from: holder }); + }); + + it('deposit', async function () { + expect(await this.vault.previewDeposit(amountWithFees)).to.be.bignumber.equal(amountWithoutFees); + ({ tx: this.tx } = await this.vault.deposit(amountWithFees, recipient, { from: holder })); + }); + + it('mint', async function () { + expect(await this.vault.previewMint(amountWithoutFees)).to.be.bignumber.equal(amountWithFees); + ({ tx: this.tx } = await this.vault.mint(amountWithoutFees, recipient, { from: holder })); + }); + + afterEach(async function () { + // get total + await expectEvent.inTransaction(this.tx, this.token, 'Transfer', { + from: holder, + to: this.vault.address, + value: amountWithFees, + }); + + // redirect fees + await expectEvent.inTransaction(this.tx, this.token, 'Transfer', { + from: this.vault.address, + to: other, + value: fees, + }); + + // mint shares + await expectEvent.inTransaction(this.tx, this.vault, 'Transfer', { + from: constants.ZERO_ADDRESS, + to: recipient, + value: amountWithoutFees, + }); + + // deposit event + await expectEvent.inTransaction(this.tx, this.vault, 'Deposit', { + sender: holder, + owner: recipient, + assets: amountWithFees, + shares: amountWithoutFees, + }); + }); + }); + + describe('output fees', function () { + beforeEach(async function () { + this.token = await ERC20Decimals.new(name, symbol, 18); + this.vault = await ERC4626FeesMock.new( + name + ' Vault', + symbol + 'V', + this.token.address, + 0, + constants.ZERO_ADDRESS, + 5e3, // 5% + other, + ); + + await this.token.$_mint(this.vault.address, constants.MAX_INT256); + await this.vault.$_mint(holder, constants.MAX_INT256); + }); + + it('redeem', async function () { + expect(await this.vault.previewRedeem(amountWithFees)).to.be.bignumber.equal(amountWithoutFees); + ({ tx: this.tx } = await this.vault.redeem(amountWithFees, recipient, holder, { from: holder })); + }); + + it('withdraw', async function () { + expect(await this.vault.previewWithdraw(amountWithoutFees)).to.be.bignumber.equal(amountWithFees); + ({ tx: this.tx } = await this.vault.withdraw(amountWithoutFees, recipient, holder, { from: holder })); + }); + + afterEach(async function () { + // withdraw principal + await expectEvent.inTransaction(this.tx, this.token, 'Transfer', { + from: this.vault.address, + to: recipient, + value: amountWithoutFees, + }); + + // redirect fees + await expectEvent.inTransaction(this.tx, this.token, 'Transfer', { + from: this.vault.address, + to: other, + value: fees, + }); + + // mint shares + await expectEvent.inTransaction(this.tx, this.vault, 'Transfer', { + from: holder, + to: constants.ZERO_ADDRESS, + value: amountWithFees, + }); + + // withdraw event + await expectEvent.inTransaction(this.tx, this.vault, 'Withdraw', { + sender: holder, + receiver: recipient, + owner: holder, + assets: amountWithoutFees, + shares: amountWithFees, + }); + }); + }); + }); + /// Scenario inspired by solmate ERC4626 tests: /// https://github.com/transmissions11/solmate/blob/main/src/test/ERC4626.t.sol it('multiple mint, deposit, redeem & withdrawal', async function () { From b4d765b130d7306fd496a4c449b6eae403173be8 Mon Sep 17 00:00:00 2001 From: Harshit sharma <79695575+HarshitSharma007@users.noreply.github.com> Date: Fri, 24 Feb 2023 20:35:46 +0530 Subject: [PATCH 054/133] Allow return data length >= 32 in SignatureChecker (#4038) Co-authored-by: Francisco Giordano --- .changeset/warm-masks-obey.md | 5 +++++ contracts/utils/cryptography/SignatureChecker.sol | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changeset/warm-masks-obey.md diff --git a/.changeset/warm-masks-obey.md b/.changeset/warm-masks-obey.md new file mode 100644 index 000000000..3bcfa9bdd --- /dev/null +++ b/.changeset/warm-masks-obey.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': minor +--- + +`SignatureChecker`: Allow return data length greater than 32 from EIP-1271 signers. diff --git a/contracts/utils/cryptography/SignatureChecker.sol b/contracts/utils/cryptography/SignatureChecker.sol index c3a724dd0..b81cf40be 100644 --- a/contracts/utils/cryptography/SignatureChecker.sol +++ b/contracts/utils/cryptography/SignatureChecker.sol @@ -44,7 +44,7 @@ library SignatureChecker { abi.encodeWithSelector(IERC1271.isValidSignature.selector, hash, signature) ); return (success && - result.length == 32 && + result.length >= 32 && abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector)); } } From 8a43ebac28a3e3ae6870387a473582064473cef1 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Fri, 24 Feb 2023 17:48:55 +0100 Subject: [PATCH 055/133] Document "duplicate" proposal storing in GovernorCompatibilityBravo (#4073) Co-authored-by: Francisco --- .../compatibility/GovernorCompatibilityBravo.sol | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/contracts/governance/compatibility/GovernorCompatibilityBravo.sol b/contracts/governance/compatibility/GovernorCompatibilityBravo.sol index 39c895bf0..25f404403 100644 --- a/contracts/governance/compatibility/GovernorCompatibilityBravo.sol +++ b/contracts/governance/compatibility/GovernorCompatibilityBravo.sol @@ -55,6 +55,7 @@ abstract contract GovernorCompatibilityBravo is IGovernorTimelock, IGovernorComp bytes[] memory calldatas, string memory description ) public virtual override(IGovernor, Governor) returns (uint256) { + // Stores the proposal details (if not already present) and executes the propose logic from the core. _storeProposal(_msgSender(), targets, values, new string[](calldatas.length), calldatas, description); return super.propose(targets, values, calldatas, description); } @@ -69,6 +70,10 @@ abstract contract GovernorCompatibilityBravo is IGovernorTimelock, IGovernorComp bytes[] memory calldatas, string memory description ) public virtual override returns (uint256) { + // Stores the full proposal and fallback to the public (possibly overridden) propose. The fallback is done + // after the full proposal is stored, so the store operation included in the fallback will be skipped. Here we + // call `propose` and not `super.propose` to make sure if a child contract override `propose`, whatever code + // is added their is also executed when calling this alternative interface. _storeProposal(_msgSender(), targets, values, signatures, calldatas, description); return propose(targets, values, _encodeCalldata(signatures, calldatas), description); } @@ -174,7 +179,7 @@ abstract contract GovernorCompatibilityBravo is IGovernorTimelock, IGovernorComp } /** - * @dev Store proposal metadata for later lookup + * @dev Store proposal metadata (if not already present) for later lookup. */ function _storeProposal( address proposer, From eb38c059d81ecf9296ef7526233ed962aba070eb Mon Sep 17 00:00:00 2001 From: Pascal Marco Caversaccio Date: Fri, 24 Feb 2023 19:34:03 +0100 Subject: [PATCH 056/133] Add comment on unchecked arithmetic (division by zero) in `Math.sol` (#4050) Co-authored-by: Francisco --- contracts/utils/math/Math.sol | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contracts/utils/math/Math.sol b/contracts/utils/math/Math.sol index 8400d0669..f8e7ca0a9 100644 --- a/contracts/utils/math/Math.sol +++ b/contracts/utils/math/Math.sol @@ -67,6 +67,9 @@ library Math { // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { + // Solidity will revert if denominator == 0, unlike the div opcode on its own. + // The surrounding unchecked block does not change this fact. + // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } From 2c6ef8c875c8b307d3e715cb918acc5c2c42714e Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Fri, 24 Feb 2023 20:14:49 +0100 Subject: [PATCH 057/133] Fix ERC1363 interfaceId (#4074) --- contracts/interfaces/IERC1363.sol | 11 +++-------- contracts/interfaces/README.adoc | 4 ++++ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/contracts/interfaces/IERC1363.sol b/contracts/interfaces/IERC1363.sol index 1a8dc79f4..1517197fe 100644 --- a/contracts/interfaces/IERC1363.sol +++ b/contracts/interfaces/IERC1363.sol @@ -8,17 +8,12 @@ import "./IERC165.sol"; interface IERC1363 is IERC165, IERC20 { /* - * Note: the ERC-165 identifier for this interface is 0x4bbee2df. - * 0x4bbee2df === + * Note: the ERC-165 identifier for this interface is 0xb0202a11. + * 0xb0202a11 === * bytes4(keccak256('transferAndCall(address,uint256)')) ^ * bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^ * bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^ - * bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) - */ - - /* - * Note: the ERC-165 identifier for this interface is 0xfb9ec8ce. - * 0xfb9ec8ce === + * bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^ * bytes4(keccak256('approveAndCall(address,uint256)')) ^ * bytes4(keccak256('approveAndCall(address,uint256,bytes)')) */ diff --git a/contracts/interfaces/README.adoc b/contracts/interfaces/README.adoc index 8748da8a4..710c078e8 100644 --- a/contracts/interfaces/README.adoc +++ b/contracts/interfaces/README.adoc @@ -22,6 +22,8 @@ are useful to interact with third party contracts that implement them. - {IERC1155MetadataURI} - {IERC1271} - {IERC1363} +- {IERC1363Receiver} +- {IERC1363Spender} - {IERC1820Implementer} - {IERC1820Registry} - {IERC1822Proxiable} @@ -44,6 +46,8 @@ are useful to interact with third party contracts that implement them. {{IERC1363Receiver}} +{{IERC1363Spender}} + {{IERC1820Implementer}} {{IERC1820Registry}} From 0fbd039554c05f2872639850d0e0127587551946 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 Feb 2023 17:14:21 -0300 Subject: [PATCH 058/133] Update lockfile (#4018) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package-lock.json | 7545 ++++++++++++++++----------------------------- 1 file changed, 2719 insertions(+), 4826 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4f808cf30..87fd3a795 100644 --- a/package-lock.json +++ b/package-lock.json @@ -86,81 +86,10 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/runtime": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.7.tgz", - "integrity": "sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", + "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", "dev": true, "dependencies": { "regenerator-runtime": "^0.13.11" @@ -190,24 +119,6 @@ "semver": "^5.4.1" } }, - "node_modules/@changesets/apply-release-plan/node_modules/detect-indent": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", - "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@changesets/apply-release-plan/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/@changesets/apply-release-plan/node_modules/semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -304,83 +215,6 @@ "changeset": "bin.js" } }, - "node_modules/@changesets/cli/node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/@changesets/cli/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@changesets/cli/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@changesets/cli/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@changesets/cli/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@changesets/cli/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@changesets/cli/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@changesets/cli/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/@changesets/cli/node_modules/semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -390,18 +224,6 @@ "semver": "bin/semver" } }, - "node_modules/@changesets/cli/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@changesets/config": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@changesets/config/-/config-2.3.0.tgz", @@ -439,65 +261,6 @@ "semver": "^5.4.1" } }, - "node_modules/@changesets/get-dependents-graph/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@changesets/get-dependents-graph/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@changesets/get-dependents-graph/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@changesets/get-dependents-graph/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@changesets/get-dependents-graph/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@changesets/get-dependents-graph/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/@changesets/get-dependents-graph/node_modules/semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -507,18 +270,6 @@ "semver": "bin/semver" } }, - "node_modules/@changesets/get-dependents-graph/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@changesets/get-github-info": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/@changesets/get-github-info/-/get-github-info-0.5.2.tgz", @@ -574,77 +325,6 @@ "chalk": "^2.1.0" } }, - "node_modules/@changesets/logger/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@changesets/logger/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@changesets/logger/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@changesets/logger/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@changesets/logger/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@changesets/logger/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@changesets/logger/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@changesets/parse": { "version": "0.3.16", "resolved": "https://registry.npmjs.org/@changesets/parse/-/parse-0.3.16.tgz", @@ -684,77 +364,6 @@ "p-filter": "^2.1.0" } }, - "node_modules/@changesets/read/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@changesets/read/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@changesets/read/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@changesets/read/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@changesets/read/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@changesets/read/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@changesets/read/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@changesets/types": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/@changesets/types/-/types-5.2.1.tgz", @@ -1730,12 +1339,6 @@ "fs-extra": "^8.1.0" } }, - "node_modules/@manypkg/find-root/node_modules/@types/node": { - "version": "12.20.55", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", - "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", - "dev": true - }, "node_modules/@manypkg/find-root/node_modules/fs-extra": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", @@ -1784,26 +1387,6 @@ "node": ">=6 <7 || >=8" } }, - "node_modules/@manypkg/get-packages/node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@metamask/eth-sig-util": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz", @@ -1845,9 +1428,9 @@ } }, "node_modules/@noble/hashes": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.1.2.tgz", - "integrity": "sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", + "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==", "dev": true, "funding": [ { @@ -1857,9 +1440,9 @@ ] }, "node_modules/@noble/secp256k1": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.6.3.tgz", - "integrity": "sha512-T04e4iTurVy7I8Sw4+c5OSN9/RkPlo1uKxAomtxQNLq8j1uPAqnsqG1bqvY3Jv7c13gyr6dui0zmh/I3+f/JaQ==", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", "dev": true, "funding": [ { @@ -2087,9 +1670,9 @@ } }, "node_modules/@nomicfoundation/hardhat-network-helpers": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.0.7.tgz", - "integrity": "sha512-X+3mNvn8B7BY5hpIaLO+TrfzWq12bpux+ajGGdmdcfC78NXmYmOZkAtiz1QZx1YIZGMS1LaXzPXyBExxKFpCaw==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.0.8.tgz", + "integrity": "sha512-MNqQbzUJZnCMIYvlniC3U+kcavz/PhhQSsY90tbEtUyMj/IQqsLwIRZa4ctjABh3Bz0KCh9OXUZ7Yk/d9hr45Q==", "dev": true, "dependencies": { "ethereumjs-util": "^7.1.4" @@ -2379,6 +1962,73 @@ "oz-docs": "oz-docs.js" } }, + "node_modules/@openzeppelin/docs-utils/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@openzeppelin/docs-utils/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@openzeppelin/docs-utils/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@openzeppelin/docs-utils/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@openzeppelin/docs-utils/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@openzeppelin/docs-utils/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@openzeppelin/test-helpers": { "version": "0.5.16", "resolved": "https://registry.npmjs.org/@openzeppelin/test-helpers/-/test-helpers-0.5.16.tgz", @@ -2397,6 +2047,15 @@ "web3-utils": "^1.2.5" } }, + "node_modules/@openzeppelin/test-helpers/node_modules/ansi-colors": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", + "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/@openzeppelin/test-helpers/node_modules/semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -2407,9 +2066,9 @@ } }, "node_modules/@openzeppelin/upgrades-core": { - "version": "1.20.6", - "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades-core/-/upgrades-core-1.20.6.tgz", - "integrity": "sha512-KWdtlahm+iunlAlzLsdpBueanwEx0LLPfAkDL1p0C4SPjMiUqHHFlyGtmmWwdiqDpJ//605vfwkd5RqfnFrHSg==", + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades-core/-/upgrades-core-1.24.0.tgz", + "integrity": "sha512-lXf1tUrCZ3Q/YmWhw0cuSSOHMp0OAsmeOg1fhSGEM6nQQ6cIVlFvq2pCV5hZMb7xkOm5pmmzV8JW1W3kfW6Lfw==", "dev": true, "dependencies": { "cbor": "^8.0.0", @@ -2421,16 +2080,19 @@ "solidity-ast": "^0.4.15" } }, - "node_modules/@openzeppelin/upgrades-core/node_modules/cbor": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/cbor/-/cbor-8.1.0.tgz", - "integrity": "sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==", + "node_modules/@openzeppelin/upgrades-core/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "nofilter": "^3.1.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=12.19" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/@openzeppelin/upgrades-core/node_modules/chalk": { @@ -2449,13 +2111,43 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@openzeppelin/upgrades-core/node_modules/nofilter": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz", - "integrity": "sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==", + "node_modules/@openzeppelin/upgrades-core/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@openzeppelin/upgrades-core/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@openzeppelin/upgrades-core/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "engines": { - "node": ">=12.19" + "node": ">=8" + } + }, + "node_modules/@openzeppelin/upgrades-core/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, "node_modules/@scure/base": { @@ -2471,9 +2163,9 @@ ] }, "node_modules/@scure/bip32": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.0.tgz", - "integrity": "sha512-ftTW3kKX54YXLCxH6BB7oEEoJfoE2pIgw7MINKAs5PsS6nqKPuKk1haTF/EuHmYqG330t5GSrdmtRuHaY1a62Q==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz", + "integrity": "sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==", "dev": true, "funding": [ { @@ -2482,15 +2174,15 @@ } ], "dependencies": { - "@noble/hashes": "~1.1.1", - "@noble/secp256k1": "~1.6.0", + "@noble/hashes": "~1.2.0", + "@noble/secp256k1": "~1.7.0", "@scure/base": "~1.1.0" } }, "node_modules/@scure/bip39": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.0.tgz", - "integrity": "sha512-pwrPOS16VeTKg98dYXQyIjJEcWfz7/1YJIwxUEPFfQPtc86Ym/1sVgQ2RLoD43AazMk2l/unK4ITySSpW2+82w==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz", + "integrity": "sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==", "dev": true, "funding": [ { @@ -2499,7 +2191,7 @@ } ], "dependencies": { - "@noble/hashes": "~1.1.1", + "@noble/hashes": "~1.2.0", "@scure/base": "~1.1.0" } }, @@ -2639,14 +2331,14 @@ } }, "node_modules/@truffle/abi-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@truffle/abi-utils/-/abi-utils-0.3.6.tgz", - "integrity": "sha512-61aTH2QmwVA1INaPMufRHTsS6jsEhS+GCkuCDdvBDmwctSnCKGDOr185BGt65QrpMRxYmIoH6WFBSNMYxW9GRw==", + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@truffle/abi-utils/-/abi-utils-0.3.8.tgz", + "integrity": "sha512-RevMtlEuQw9cE2VWzQuvLDSYPCVSZQQUOsaK8ArcwxXct6ugiJCDC7tNouhHzP1Y4ccdZtG2y/XPHQJdzgYdZQ==", "dev": true, "dependencies": { "change-case": "3.0.2", "fast-check": "3.1.1", - "web3-utils": "1.8.1" + "web3-utils": "1.8.2" } }, "node_modules/@truffle/blockchain-utils": { @@ -2656,13 +2348,13 @@ "dev": true }, "node_modules/@truffle/codec": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/@truffle/codec/-/codec-0.14.11.tgz", - "integrity": "sha512-NgfMNYemgMXqoEcJA5ZsEhxChCwq33rSxtNxlececEH/1Nf0r+ryfrfmLlyPmv8f3jorVf1GWa0zI0AedGCGYQ==", + "version": "0.14.15", + "resolved": "https://registry.npmjs.org/@truffle/codec/-/codec-0.14.15.tgz", + "integrity": "sha512-cooWy8blmvYQQRBKgzWJnDUS6mZE9cvnmpVN15jU6TseAQkBtmfYfCH12QCKEWMq2+R4yQICP54WNCYg78g72g==", "dev": true, "dependencies": { - "@truffle/abi-utils": "^0.3.6", - "@truffle/compile-common": "^0.9.1", + "@truffle/abi-utils": "^0.3.8", + "@truffle/compile-common": "^0.9.3", "big.js": "^6.0.3", "bn.js": "^5.1.3", "cbor": "^5.2.0", @@ -2670,7 +2362,16 @@ "lodash": "^4.17.21", "semver": "7.3.7", "utf8": "^3.0.0", - "web3-utils": "1.8.1" + "web3-utils": "1.8.2" + } + }, + "node_modules/@truffle/codec/node_modules/bignumber.js": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz", + "integrity": "sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig==", + "dev": true, + "engines": { + "node": "*" } }, "node_modules/@truffle/codec/node_modules/bn.js": { @@ -2679,6 +2380,19 @@ "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", "dev": true }, + "node_modules/@truffle/codec/node_modules/cbor": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/cbor/-/cbor-5.2.0.tgz", + "integrity": "sha512-5IMhi9e1QU76ppa5/ajP1BmMWZ2FHkhAhjeVKQ/EFCgYSEaeVaoGtL7cxJskf9oCCk+XjzaIdc3IuU/dbA/o2A==", + "dev": true, + "dependencies": { + "bignumber.js": "^9.0.1", + "nofilter": "^1.0.4" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@truffle/codec/node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -2691,6 +2405,15 @@ "node": ">=10" } }, + "node_modules/@truffle/codec/node_modules/nofilter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-1.0.4.tgz", + "integrity": "sha512-N8lidFp+fCz+TD51+haYdbDGrcBWwuHX40F5+z0qkUjMJ5Tp+rdSuAkMJ9N9eoolDlEVTf6u5icM+cNKkKW2mA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/@truffle/codec/node_modules/semver": { "version": "7.3.7", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", @@ -2713,71 +2436,71 @@ "dev": true }, "node_modules/@truffle/compile-common": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/@truffle/compile-common/-/compile-common-0.9.1.tgz", - "integrity": "sha512-mhdkX6ExZImHSBO3jGm6aAn8NpVtMTdjq50jRXY/O59/ZNC0J9WpRapxrAKUVNc+XydMdBlfeEpXoqTJg7cbXw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/@truffle/compile-common/-/compile-common-0.9.3.tgz", + "integrity": "sha512-9S86H5DRC0zEj164KeClP/6jVt1M/nRd7St89h6QbuIU0JjpqSz1SXpkvqhbFoV9hhW+4ZGh0NysjrdPlk7gFw==", "dev": true, "dependencies": { - "@truffle/error": "^0.1.1", + "@truffle/error": "^0.2.0", "colors": "1.4.0" } }, + "node_modules/@truffle/compile-common/node_modules/@truffle/error": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@truffle/error/-/error-0.2.0.tgz", + "integrity": "sha512-Fe0/z4WWb7IP2gBnv3l6zqP87Y0kSMs7oiSLakKJq17q3GUunrHSdioKuNspdggxkXIBhEQLhi8C+LJdwmHKWQ==", + "dev": true + }, "node_modules/@truffle/contract": { - "version": "4.6.10", - "resolved": "https://registry.npmjs.org/@truffle/contract/-/contract-4.6.10.tgz", - "integrity": "sha512-69IZSXeQKRP3EutILqe+vLY5A5gUpeXUiZhm/Fy/qHHkP238vMjtOkTZGkY6bonYqmgk+vDY7KSYSYKzDNPdCA==", + "version": "4.6.15", + "resolved": "https://registry.npmjs.org/@truffle/contract/-/contract-4.6.15.tgz", + "integrity": "sha512-3V+50z94XRh+I3axz6Zrot1wlMhRiG2O9XjR20LwR5YBnzHV7YFfOs8x6pluXVLQyxcVJBISJyqxvGxpkecrZg==", "dev": true, "dependencies": { "@ensdomains/ensjs": "^2.1.0", "@truffle/blockchain-utils": "^0.1.6", - "@truffle/contract-schema": "^3.4.11", - "@truffle/debug-utils": "^6.0.42", - "@truffle/error": "^0.1.1", - "@truffle/interface-adapter": "^0.5.26", + "@truffle/contract-schema": "^3.4.12", + "@truffle/debug-utils": "^6.0.46", + "@truffle/error": "^0.2.0", + "@truffle/interface-adapter": "^0.5.29", "bignumber.js": "^7.2.1", "debug": "^4.3.1", "ethers": "^4.0.32", - "web3": "1.8.1", - "web3-core-helpers": "1.8.1", - "web3-core-promievent": "1.8.1", - "web3-eth-abi": "1.8.1", - "web3-utils": "1.8.1" + "web3": "1.8.2", + "web3-core-helpers": "1.8.2", + "web3-core-promievent": "1.8.2", + "web3-eth-abi": "1.8.2", + "web3-utils": "1.8.2" } }, "node_modules/@truffle/contract-schema": { - "version": "3.4.11", - "resolved": "https://registry.npmjs.org/@truffle/contract-schema/-/contract-schema-3.4.11.tgz", - "integrity": "sha512-wReyVZUPyU9Zy5PSCugBLG1nnruBmRAJ/gmoirQiJ9N2n+s1iGBTY49tkDqFMz3XUUE0kplfdb9YKZJlLkTWzQ==", + "version": "3.4.12", + "resolved": "https://registry.npmjs.org/@truffle/contract-schema/-/contract-schema-3.4.12.tgz", + "integrity": "sha512-XpMMps/bqHwiRuCyLiEEGWEAvGGzGj4u1X1+lzxrtIsrwbQhSZcdgEbXl9vGxOOJWOup3HXRCIsjlao27kS4OA==", "dev": true, "dependencies": { "ajv": "^6.10.0", "debug": "^4.3.1" } }, + "node_modules/@truffle/contract/node_modules/@truffle/error": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@truffle/error/-/error-0.2.0.tgz", + "integrity": "sha512-Fe0/z4WWb7IP2gBnv3l6zqP87Y0kSMs7oiSLakKJq17q3GUunrHSdioKuNspdggxkXIBhEQLhi8C+LJdwmHKWQ==", + "dev": true + }, "node_modules/@truffle/debug-utils": { - "version": "6.0.42", - "resolved": "https://registry.npmjs.org/@truffle/debug-utils/-/debug-utils-6.0.42.tgz", - "integrity": "sha512-9v70tj+My0Z2UZJ9OsuUlfo4Dt2AJqAQa/YWtGe28H8zsi+o9Dca0RsKWecuprdllgzrEs7ad8QUtSINhwjIlg==", + "version": "6.0.46", + "resolved": "https://registry.npmjs.org/@truffle/debug-utils/-/debug-utils-6.0.46.tgz", + "integrity": "sha512-MWko3c1M0NI8IT0yNh8Dh2xoDgR2R1apP8hc/9VsR/4Q7P6OE/578WRpZnvo2HWXYBiJ2PrWBDtMYBHntImrrA==", "dev": true, "dependencies": { - "@truffle/codec": "^0.14.11", + "@truffle/codec": "^0.14.15", "@trufflesuite/chromafi": "^3.0.0", "bn.js": "^5.1.3", "chalk": "^2.4.2", "debug": "^4.3.1", - "highlightjs-solidity": "^2.0.5" - } - }, - "node_modules/@truffle/debug-utils/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" + "highlightjs-solidity": "^2.0.6" } }, "node_modules/@truffle/debug-utils/node_modules/bn.js": { @@ -2786,65 +2509,6 @@ "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", "dev": true }, - "node_modules/@truffle/debug-utils/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@truffle/debug-utils/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@truffle/debug-utils/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@truffle/debug-utils/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@truffle/debug-utils/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@truffle/debug-utils/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@truffle/error": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@truffle/error/-/error-0.1.1.tgz", @@ -2852,14 +2516,14 @@ "dev": true }, "node_modules/@truffle/interface-adapter": { - "version": "0.5.26", - "resolved": "https://registry.npmjs.org/@truffle/interface-adapter/-/interface-adapter-0.5.26.tgz", - "integrity": "sha512-fBhoqtT+CT4XKXcOijvw0RIMgyUi3FJg+n5i5PyGBsoRzqbLZd9cZq+oMNjOZPdf3GH68hsOFOaQO5tZH7oZow==", + "version": "0.5.29", + "resolved": "https://registry.npmjs.org/@truffle/interface-adapter/-/interface-adapter-0.5.29.tgz", + "integrity": "sha512-6UlJ+f87z7y/dWk9UfbIU+4e80iRsp8h03LEiE5B+PvZbr6cuMjLJUBtBBQZMo3+xrIcS/2u3p5hOxW8OJm8tw==", "dev": true, "dependencies": { "bn.js": "^5.1.3", "ethers": "^4.0.32", - "web3": "1.8.1" + "web3": "1.8.2" } }, "node_modules/@truffle/interface-adapter/node_modules/bn.js": { @@ -2884,73 +2548,11 @@ "strip-indent": "^2.0.0" } }, - "node_modules/@trufflesuite/chromafi/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "node_modules/@trufflesuite/chromafi/node_modules/detect-indent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz", + "integrity": "sha512-rlpvsxUtM0PQvy9iZe640/IWwWYyBsTApREbA1pHOpmOUIl9MkP/U4z7vTtg4Oaojvqhxt7sdufnT0EzGaR31g==", "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@trufflesuite/chromafi/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@trufflesuite/chromafi/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@trufflesuite/chromafi/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@trufflesuite/chromafi/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@trufflesuite/chromafi/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@trufflesuite/chromafi/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, "engines": { "node": ">=4" } @@ -3041,21 +2643,6 @@ "ci-info": "^3.1.0" } }, - "node_modules/@types/is-ci/node_modules/ci-info": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.1.tgz", - "integrity": "sha512-4jYS4MOAaCIStSRwiuxc4B8MYhIe676yO1sYGzARnjXkWpmzZMMYxY6zu8WYWDhSuth5zhrQ1rhNSibyyvv4/w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, "node_modules/@types/keyv": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", @@ -3084,9 +2671,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.11.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz", - "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==", + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", "dev": true }, "node_modules/@types/normalize-package-data": { @@ -3214,9 +2801,9 @@ } }, "node_modules/acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -3310,9 +2897,9 @@ } }, "node_modules/ansi-colors": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", - "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true, "engines": { "node": ">=6" @@ -3355,25 +2942,25 @@ } }, "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "color-convert": "^1.9.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=4" } }, "node_modules/antlr4": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.7.1.tgz", - "integrity": "sha512-haHyTW7Y9joE5MVs37P2lNYfU2RWBLfcRDD8OWldcdZm5TiCE91B5Xl1oWSwiDUSd4rlExpt2pu1fksYQjRBYQ==", - "dev": true + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.12.0.tgz", + "integrity": "sha512-23iB5IzXJZRZeK9TigzUyrNc9pSmNqAerJRBcNq1ETrmttMWRgaYZzC561IgEO3ygKsDJTYDTozABXa4b/fTQQ==", + "dev": true, + "engines": { + "node": ">=16" + } }, "node_modules/antlr4ts": { "version": "0.5.0-alpha.4", @@ -3488,18 +3075,6 @@ "safer-buffer": "~2.1.0" } }, - "node_modules/asn1.js": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", - "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", - "dev": true, - "dependencies": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "safer-buffer": "^2.1.0" - } - }, "node_modules/assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", @@ -3525,12 +3100,12 @@ "dev": true }, "node_modules/astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/async": { @@ -3585,9 +3160,9 @@ } }, "node_modules/aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", + "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", "dev": true }, "node_modules/balanced-match": { @@ -3738,13 +3313,13 @@ "dev": true }, "node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "dev": true, "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", @@ -3752,7 +3327,7 @@ "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.11.0", - "raw-body": "2.5.1", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -3851,68 +3426,6 @@ "safe-buffer": "^5.0.1" } }, - "node_modules/browserify-cipher": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", - "dev": true, - "dependencies": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "node_modules/browserify-des": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", - "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", - "dev": true, - "dependencies": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/browserify-rsa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", - "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", - "dev": true, - "dependencies": { - "bn.js": "^5.0.0", - "randombytes": "^2.0.1" - } - }, - "node_modules/browserify-rsa/node_modules/bn.js": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", - "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", - "dev": true - }, - "node_modules/browserify-sign": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", - "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", - "dev": true, - "dependencies": { - "bn.js": "^5.1.1", - "browserify-rsa": "^4.0.1", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "elliptic": "^6.5.3", - "inherits": "^2.0.4", - "parse-asn1": "^5.1.5", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - } - }, - "node_modules/browserify-sign/node_modules/bn.js": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", - "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", - "dev": true - }, "node_modules/bs58": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", @@ -4079,39 +3592,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/caller-callsite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", - "integrity": "sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ==", - "dev": true, - "dependencies": { - "callsites": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/caller-callsite/node_modules/callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/caller-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A==", - "dev": true, - "dependencies": { - "caller-callsite": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -4166,15 +3646,6 @@ "node": ">=6" } }, - "node_modules/camelcase-keys/node_modules/quick-lru": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", - "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -4191,25 +3662,15 @@ } }, "node_modules/cbor": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/cbor/-/cbor-5.2.0.tgz", - "integrity": "sha512-5IMhi9e1QU76ppa5/ajP1BmMWZ2FHkhAhjeVKQ/EFCgYSEaeVaoGtL7cxJskf9oCCk+XjzaIdc3IuU/dbA/o2A==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/cbor/-/cbor-8.1.0.tgz", + "integrity": "sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==", "dev": true, "dependencies": { - "bignumber.js": "^9.0.1", - "nofilter": "^1.0.4" + "nofilter": "^3.1.0" }, "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/cbor/node_modules/bignumber.js": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz", - "integrity": "sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig==", - "dev": true, - "engines": { - "node": "*" + "node": ">=12.19" } }, "node_modules/chai": { @@ -4241,16 +3702,17 @@ } }, "node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/change-case": { @@ -4375,10 +3837,19 @@ "dev": true }, "node_modules/ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } }, "node_modules/cids": { "version": "0.7.5", @@ -4451,18 +3922,6 @@ "node": ">=6" } }, - "node_modules/cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", - "dev": true, - "dependencies": { - "restore-cursor": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/cli-table3": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz", @@ -4479,12 +3938,6 @@ "colors": "^1.1.2" } }, - "node_modules/cli-width": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", - "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", - "dev": true - }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -4574,21 +4027,18 @@ } }, "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" + "color-name": "1.1.3" } }, "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, "node_modules/colors": { @@ -4619,10 +4069,13 @@ "dev": true }, "node_modules/commander": { - "version": "2.18.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.18.0.tgz", - "integrity": "sha512-6CYPa+JP2ftfRU2qkDK+UTVeQYosOg/2GbcjIcKPHfinyOLPVGXu/ovN86RP49Re5ndJK1N0kuiidFFuepc4ZQ==", - "dev": true + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.0.tgz", + "integrity": "sha512-zS5PnTI22FIRM6ylNW8G4Ap0IEOyk62fhLSD0+uHRT9McRCLGpkVNvao4bjimpK/GShynyQkFFxHhwMcETmduA==", + "dev": true, + "engines": { + "node": ">=14" + } }, "node_modules/compare-versions": { "version": "5.0.3", @@ -4652,9 +4105,9 @@ } }, "node_modules/concat-stream/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "dependencies": { "core-util-is": "~1.0.0", @@ -4715,9 +4168,9 @@ } }, "node_modules/content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "dev": true, "engines": { "node": ">= 0.6" @@ -4758,40 +4211,36 @@ } }, "node_modules/cosmiconfig": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", - "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.0.0.tgz", + "integrity": "sha512-da1EafcpH6b/TD8vDRaWV7xFINlHlF6zKsGwS1TsuVJTZRkquaS5HTMq7uq6h31619QjbsYl21gVDOm32KM1vQ==", "dev": true, "dependencies": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.0.0" + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0" }, "engines": { - "node": ">=4" + "node": ">=14" } }, - "node_modules/cosmiconfig/node_modules/import-fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==", + "node_modules/cosmiconfig/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/cosmiconfig/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "dependencies": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" + "argparse": "^2.0.1" }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cosmiconfig/node_modules/resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", - "dev": true, - "engines": { - "node": ">=4" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, "node_modules/crc-32": { @@ -4806,16 +4255,6 @@ "node": ">=0.8" } }, - "node_modules/create-ecdh": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", - "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", - "dev": true, - "dependencies": { - "bn.js": "^4.1.0", - "elliptic": "^6.5.3" - } - }, "node_modules/create-hash": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", @@ -4852,6 +4291,26 @@ "node-fetch": "2.6.7" } }, + "node_modules/cross-fetch/node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -4890,28 +4349,6 @@ "sha3": "^2.1.1" } }, - "node_modules/crypto-browserify": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", - "dev": true, - "dependencies": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" - }, - "engines": { - "node": "*" - } - }, "node_modules/crypto-js": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.3.0.tgz", @@ -5031,15 +4468,12 @@ } }, "node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", "dev": true, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, "node_modules/decamelize-keys": { @@ -5058,15 +4492,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/decamelize-keys/node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/decamelize-keys/node_modules/map-obj": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", @@ -5152,9 +4577,9 @@ } }, "node_modules/define-properties": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", - "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", "dev": true, "dependencies": { "has-property-descriptors": "^1.0.0", @@ -5185,16 +4610,6 @@ "node": ">= 0.8" } }, - "node_modules/des.js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", - "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, "node_modules/destroy": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", @@ -5206,12 +4621,12 @@ } }, "node_modules/detect-indent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz", - "integrity": "sha512-rlpvsxUtM0PQvy9iZe640/IWwWYyBsTApREbA1pHOpmOUIl9MkP/U4z7vTtg4Oaojvqhxt7sdufnT0EzGaR31g==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", "dev": true, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/detect-port": { @@ -5237,17 +4652,6 @@ "node": ">=0.3.1" } }, - "node_modules/diffie-hellman": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", - "dev": true, - "dependencies": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - } - }, "node_modules/difflib": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/difflib/-/difflib-0.2.4.tgz", @@ -5430,15 +4834,6 @@ "node": ">=8.6" } }, - "node_modules/enquirer/node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/entities": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", @@ -5470,27 +4865,33 @@ } }, "node_modules/es-abstract": { - "version": "1.20.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.5.tgz", - "integrity": "sha512-7h8MM2EQhsCA7pU/Nv78qOXFpD8Rhqd12gYiSJVkrH9+e8VuA8JlPJK/hQjjlLv6pJvx/z1iRFKzYb0XT/RuAQ==", + "version": "1.21.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.1.tgz", + "integrity": "sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==", "dev": true, "dependencies": { + "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "function.prototype.name": "^1.1.5", "get-intrinsic": "^1.1.3", "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", "gopd": "^1.0.1", "has": "^1.0.3", "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", + "internal-slot": "^1.0.4", + "is-array-buffer": "^3.0.1", "is-callable": "^1.2.7", "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", "is-weakref": "^1.0.2", "object-inspect": "^1.12.2", "object-keys": "^1.1.1", @@ -5499,25 +4900,9 @@ "safe-regex-test": "^1.0.0", "string.prototype.trimend": "^1.0.6", "string.prototype.trimstart": "^1.0.6", - "unbox-primitive": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-abstract/node_modules/object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.9" }, "engines": { "node": ">= 0.4" @@ -5532,6 +4917,20 @@ "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", "dev": true }, + "node_modules/es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-shim-unscopables": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", @@ -5616,15 +5015,12 @@ "dev": true }, "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.8.0" } }, "node_modules/escodegen": { @@ -5723,9 +5119,9 @@ } }, "node_modules/eslint": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.31.0.tgz", - "integrity": "sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==", + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.34.0.tgz", + "integrity": "sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==", "dev": true, "dependencies": { "@eslint/eslintrc": "^1.4.1", @@ -5848,6 +5244,21 @@ "node": ">=8" } }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/eslint/node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -5870,6 +5281,36 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/eslint/node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -5898,6 +5339,15 @@ "node": ">=10.13.0" } }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/eslint/node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -5967,6 +5417,18 @@ "node": ">=8" } }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/espree": { "version": "9.4.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", @@ -5998,9 +5460,9 @@ } }, "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.2.tgz", + "integrity": "sha512-JVSoLdTlTDkmjFmab7H/9SL9qGSyjElT3myyKp7krqjVFQCDLmj1QFaCLRFBszBKI0XVZaiiXvuPIX3ZwHe1Ng==", "dev": true, "dependencies": { "estraverse": "^5.1.0" @@ -6113,18 +5575,6 @@ "node": ">=6" } }, - "node_modules/eth-gas-reporter/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/eth-gas-reporter/node_modules/camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", @@ -6134,32 +5584,6 @@ "node": ">=6" } }, - "node_modules/eth-gas-reporter/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eth-gas-reporter/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/eth-gas-reporter/node_modules/chokidar": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", @@ -6192,21 +5616,6 @@ "wrap-ansi": "^5.1.0" } }, - "node_modules/eth-gas-reporter/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/eth-gas-reporter/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, "node_modules/eth-gas-reporter/node_modules/debug": { "version": "3.2.6", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", @@ -6217,15 +5626,6 @@ "ms": "^2.1.1" } }, - "node_modules/eth-gas-reporter/node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/eth-gas-reporter/node_modules/diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", @@ -6241,25 +5641,16 @@ "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "dev": true }, - "node_modules/eth-gas-reporter/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/eth-gas-reporter/node_modules/ethereum-cryptography": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.1.2.tgz", - "integrity": "sha512-XDSJlg4BD+hq9N2FjvotwUET9Tfxpxc3kWGE2AqUG5vcbeunnbImVk3cj6e/xT3phdW21mE8R5IugU4fspQDcQ==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz", + "integrity": "sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==", "dev": true, "dependencies": { - "@noble/hashes": "1.1.2", - "@noble/secp256k1": "1.6.3", - "@scure/bip32": "1.1.0", - "@scure/bip39": "1.1.0" + "@noble/hashes": "1.2.0", + "@noble/secp256k1": "1.7.1", + "@scure/bip32": "1.1.5", + "@scure/bip39": "1.1.1" } }, "node_modules/eth-gas-reporter/node_modules/find-up": { @@ -6318,15 +5709,6 @@ "node": "*" } }, - "node_modules/eth-gas-reporter/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/eth-gas-reporter/node_modules/js-yaml": { "version": "3.13.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", @@ -6438,6 +5820,21 @@ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", "dev": true }, + "node_modules/eth-gas-reporter/node_modules/object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/eth-gas-reporter/node_modules/p-locate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", @@ -6961,6 +6358,30 @@ "node": ">= 0.10.0" } }, + "node_modules/express/node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, "node_modules/express/node_modules/cookie": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", @@ -6985,6 +6406,21 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, + "node_modules/express/node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/ext": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", @@ -7100,27 +6536,6 @@ "reusify": "^1.0.4" } }, - "node_modules/figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/figures/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -7418,9 +6833,9 @@ } }, "node_modules/get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", "dev": true, "dependencies": { "function-bind": "^1.1.1", @@ -7490,81 +6905,10 @@ "testrpc-sc": "index.js" } }, - "node_modules/ghost-testrpc/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/ghost-testrpc/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/ghost-testrpc/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/ghost-testrpc/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/ghost-testrpc/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/ghost-testrpc/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/ghost-testrpc/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/glob": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", - "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", @@ -7602,9 +6946,9 @@ } }, "node_modules/glob/node_modules/minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -7662,9 +7006,9 @@ } }, "node_modules/globals": { - "version": "13.19.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", - "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -7676,43 +7020,39 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/globby": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz", - "integrity": "sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==", + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, "dependencies": { - "@types/glob": "^7.1.1", "array-union": "^2.1.0", "dir-glob": "^3.0.1", - "fast-glob": "^3.0.3", - "glob": "^7.1.3", - "ignore": "^5.1.1", - "merge2": "^1.2.3", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", "slash": "^3.0.0" }, "engines": { - "node": ">=8" - } - }, - "node_modules/globby/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/gopd": { @@ -7847,9 +7187,9 @@ } }, "node_modules/hardhat": { - "version": "2.12.5", - "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.12.5.tgz", - "integrity": "sha512-f/t7+hLlhsnQZ6LDXyV+8rHGRZFZY1sgFvgrwr9fBjMdGp1Bu6hHq1KXS4/VFZfZcVdL1DAWWEkryinZhqce+A==", + "version": "2.12.7", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.12.7.tgz", + "integrity": "sha512-voWoN6zn5d8BOEaczSyK/1PyfdeOeI3SbGCFb36yCHTJUt6OIqLb+ZDX30VhA1UsYKzLqG7UnWl3fKJUuANc6A==", "dev": true, "dependencies": { "@ethersproject/abi": "^5.1.2", @@ -7899,7 +7239,7 @@ "source-map-support": "^0.5.13", "stacktrace-parser": "^0.1.10", "tsort": "0.0.1", - "undici": "^5.4.0", + "undici": "^5.14.0", "uuid": "^8.3.2", "ws": "^7.4.6" }, @@ -7923,9 +7263,9 @@ } }, "node_modules/hardhat-exposed": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/hardhat-exposed/-/hardhat-exposed-0.3.1.tgz", - "integrity": "sha512-qyHXdS3NmzrtXF+XL547BMsTAK+IEMW9OOYMH4d362DlPn4L2B2KXKG6OpuJczxYjgMFJ0LunLxNgu6jtRvjRg==", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/hardhat-exposed/-/hardhat-exposed-0.3.2.tgz", + "integrity": "sha512-qhi60I2bfjoPZwKgrY7BIpuUiBE7aC/bHN2MzHxPcZdxaeFnjKJ50n59LE7yK3GK2qYzE8DMjzqfnH6SlKPUjw==", "dev": true, "dependencies": { "micromatch": "^4.0.4", @@ -7950,9 +7290,9 @@ } }, "node_modules/hardhat-ignore-warnings": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/hardhat-ignore-warnings/-/hardhat-ignore-warnings-0.2.6.tgz", - "integrity": "sha512-GQgvjprONI8VF8b85+QJ8H9v3L9TCCtQvUx+9QaRL+sCPw1cOZHfhlEz9V6Lq7GNCQMqBORVzNzUzoP/tKAEQQ==", + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/hardhat-ignore-warnings/-/hardhat-ignore-warnings-0.2.8.tgz", + "integrity": "sha512-vPX94rJyTzYsCOzGIYdOcJgn3iQI6qa+CI9ZZfgDhdXJpda8ljpOT7bdUKAYC4LyoP0Z5fWTmupXoPaQrty0gw==", "dev": true, "dependencies": { "minimatch": "^5.1.0", @@ -7970,9 +7310,9 @@ } }, "node_modules/hardhat-ignore-warnings/node_modules/minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -7981,45 +7321,10 @@ "node": ">=10" } }, - "node_modules/hardhat/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/hardhat/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/hardhat/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/hardhat/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "node_modules/hardhat/node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", "dev": true }, "node_modules/hardhat/node_modules/commander": { @@ -8028,25 +7333,16 @@ "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==", "dev": true }, - "node_modules/hardhat/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/hardhat/node_modules/ethereum-cryptography": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.1.2.tgz", - "integrity": "sha512-XDSJlg4BD+hq9N2FjvotwUET9Tfxpxc3kWGE2AqUG5vcbeunnbImVk3cj6e/xT3phdW21mE8R5IugU4fspQDcQ==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz", + "integrity": "sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==", "dev": true, "dependencies": { - "@noble/hashes": "1.1.2", - "@noble/secp256k1": "1.6.3", - "@scure/bip32": "1.1.0", - "@scure/bip39": "1.1.0" + "@noble/hashes": "1.2.0", + "@noble/secp256k1": "1.7.1", + "@scure/bip32": "1.1.5", + "@scure/bip39": "1.1.1" } }, "node_modules/hardhat/node_modules/find-up": { @@ -8081,15 +7377,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/hardhat/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/hardhat/node_modules/jsonfile": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", @@ -8229,18 +7516,6 @@ "semver": "bin/semver" } }, - "node_modules/hardhat/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -8263,12 +7538,12 @@ } }, "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/has-property-descriptors": { @@ -8283,6 +7558,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", @@ -8369,9 +7656,9 @@ } }, "node_modules/highlightjs-solidity": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/highlightjs-solidity/-/highlightjs-solidity-2.0.5.tgz", - "integrity": "sha512-ReXxQSGQkODMUgHcWzVSnfDCDrL2HshOYgw3OlIYmfHeRzUPkfJTUIp95pK4CmbiNG2eMTOmNLpfCz9Zq7Cwmg==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/highlightjs-solidity/-/highlightjs-solidity-2.0.6.tgz", + "integrity": "sha512-DySXWfQghjm2l6a/flF+cteroJqD4gI8GSdL4PtvxZSsAHie8m3yVe2JFoRg03ROKT6hp2Lc/BxXkqerNmtQYg==", "dev": true }, "node_modules/hmac-drbg": { @@ -8496,6 +7783,18 @@ "node": ">=10.19.0" } }, + "node_modules/http2-wrapper/node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/https-proxy-agent": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", @@ -8569,9 +7868,9 @@ } }, "node_modules/immutable": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.2.1.tgz", - "integrity": "sha512-7WYV7Q5BTs0nlQm7tl92rDYYoyELLKHoDMBKhrxEoiV4mrfVdRz8hzPiYOzH7yWjzoVEamxRuAqhxL2PLRwZYQ==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.2.4.tgz", + "integrity": "sha512-WDxL3Hheb1JkRN3sQkyujNlL/xRjAo3rJtaU5xeufUauG66JdMr32bLj4gF+vWl84DIA3Zxw7tiAjneYzRRw+w==", "dev": true }, "node_modules/import-fresh": { @@ -8590,6 +7889,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -8630,138 +7938,13 @@ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true }, - "node_modules/inquirer": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", - "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", - "dev": true, - "dependencies": { - "ansi-escapes": "^3.2.0", - "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.3", - "figures": "^2.0.0", - "lodash": "^4.17.12", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^6.4.0", - "string-width": "^2.1.0", - "strip-ansi": "^5.1.0", - "through": "^2.3.6" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/inquirer/node_modules/ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer/node_modules/ansi-regex": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", - "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/inquirer/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/inquirer/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/inquirer/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/inquirer/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/inquirer/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/internal-slot": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.4.tgz", - "integrity": "sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", "dev": true, "dependencies": { - "get-intrinsic": "^1.1.3", + "get-intrinsic": "^1.2.0", "has": "^1.0.3", "side-channel": "^1.0.4" }, @@ -8821,6 +8004,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-array-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.1.tgz", + "integrity": "sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -8914,21 +8111,6 @@ "is-ci": "bin.js" } }, - "node_modules/is-ci/node_modules/ci-info": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.1.tgz", - "integrity": "sha512-4jYS4MOAaCIStSRwiuxc4B8MYhIe676yO1sYGzARnjXkWpmzZMMYxY6zu8WYWDhSuth5zhrQ1rhNSibyyvv4/w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, "node_modules/is-date-object": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", @@ -8944,15 +8126,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-directory": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -9069,12 +8242,12 @@ } }, "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", "dev": true, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, "node_modules/is-port-reachable": { @@ -9248,9 +8421,9 @@ "dev": true }, "node_modules/js-sdsl": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", - "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", + "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", "dev": true, "funding": { "type": "opencollective", @@ -9294,12 +8467,6 @@ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", @@ -9586,6 +8753,18 @@ "node": ">=0.10.0" } }, + "node_modules/load-json-file/node_modules/strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", + "dev": true, + "dependencies": { + "is-utf8": "^0.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/load-yaml-file": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/load-yaml-file/-/load-yaml-file-0.2.0.tgz", @@ -9601,15 +8780,6 @@ "node": ">=6" } }, - "node_modules/load-yaml-file/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -9652,6 +8822,12 @@ "integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==", "dev": true }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true + }, "node_modules/lodash.zip": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.zip/-/lodash.zip-4.2.0.tgz", @@ -9674,6 +8850,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/log-symbols/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -9690,6 +8881,45 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/log-symbols/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-symbols/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/loupe": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", @@ -9836,92 +9066,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/meow/node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/meow/node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/meow/node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/meow/node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/meow/node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/meow/node_modules/read-pkg-up/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/meow/node_modules/read-pkg/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/meow/node_modules/type-fest": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", @@ -9934,19 +9078,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/meow/node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -10009,19 +9140,6 @@ "node": ">=8.6" } }, - "node_modules/miller-rabin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "dev": true, - "dependencies": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - }, - "bin": { - "miller-rabin": "bin/miller-rabin" - } - }, "node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -10055,15 +9173,6 @@ "node": ">= 0.6" } }, - "node_modules/mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/mimic-response": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", @@ -10116,9 +9225,9 @@ } }, "node_modules/minimist": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", - "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -10138,15 +9247,6 @@ "node": ">= 6" } }, - "node_modules/minimist-options/node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/minipass": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", @@ -10167,9 +9267,9 @@ } }, "node_modules/mixme": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/mixme/-/mixme-0.5.4.tgz", - "integrity": "sha512-3KYa4m4Vlqx98GPdOHghxSdNtTvcP8E0kkaJ5Dlh+h2DRzF7zpuVVcA8B0QpKd11YJeP9QQ7ASkKzOeu195Wzw==", + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mixme/-/mixme-0.5.5.tgz", + "integrity": "sha512-/6IupbRx32s7jjEwHcycXikJwFD5UujbVNuJFkeKLYje+92OvtuPniF6JhnFm5JCTDUhS+kYK3W/4BWYQYXz7w==", "dev": true, "engines": { "node": ">= 8.0.0" @@ -10284,6 +9384,18 @@ "wrap-ansi": "^7.0.0" } }, + "node_modules/mocha/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/mocha/node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -10332,6 +9444,15 @@ "node": "*" } }, + "node_modules/mocha/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/mocha/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -10484,6 +9605,15 @@ "node": ">=10" } }, + "node_modules/mocha/node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/mock-fs": { "version": "4.14.0", "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-4.14.0.tgz", @@ -10548,12 +9678,6 @@ "buffer": "^5.5.0" } }, - "node_modules/mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ==", - "dev": true - }, "node_modules/nano-base32": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/nano-base32/-/nano-base32-1.0.1.tgz", @@ -10611,12 +9735,6 @@ "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", "dev": true }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, "node_modules/no-case": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", @@ -10661,9 +9779,9 @@ } }, "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", + "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", "dev": true, "dependencies": { "whatwg-url": "^5.0.0" @@ -10681,9 +9799,9 @@ } }, "node_modules/node-gyp-build": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.5.0.tgz", - "integrity": "sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz", + "integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==", "dev": true, "bin": { "node-gyp-build": "bin.js", @@ -10704,12 +9822,12 @@ } }, "node_modules/nofilter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-1.0.4.tgz", - "integrity": "sha512-N8lidFp+fCz+TD51+haYdbDGrcBWwuHX40F5+z0qkUjMJ5Tp+rdSuAkMJ9N9eoolDlEVTf6u5icM+cNKkKW2mA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz", + "integrity": "sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==", "dev": true, "engines": { - "node": ">=8" + "node": ">=12.19" } }, "node_modules/nopt": { @@ -10826,9 +9944,9 @@ } }, "node_modules/object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -10844,18 +9962,21 @@ } }, "node_modules/object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", "dev": true, "dependencies": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/object.getownpropertydescriptors": { @@ -10912,18 +10033,6 @@ "wrappy": "1" } }, - "node_modules/onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", - "dev": true, - "dependencies": { - "mimic-fn": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -11076,19 +10185,6 @@ "node": ">=6" } }, - "node_modules/parse-asn1": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", - "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", - "dev": true, - "dependencies": { - "asn1.js": "^5.2.0", - "browserify-aes": "^1.0.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3", - "safe-buffer": "^5.1.1" - } - }, "node_modules/parse-cache-control": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", @@ -11102,16 +10198,21 @@ "dev": true }, "node_modules/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "dependencies": { + "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/parse5": { @@ -11185,12 +10286,6 @@ "node": ">=0.10.0" } }, - "node_modules/path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", - "dev": true - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -11306,6 +10401,15 @@ "node": ">=8" } }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/preferred-pm": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/preferred-pm/-/preferred-pm-3.0.3.tgz", @@ -11392,9 +10496,9 @@ } }, "node_modules/prettier": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.1.tgz", - "integrity": "sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg==", + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", + "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", "dev": true, "bin": { "prettier": "bin-prettier.js" @@ -11407,12 +10511,12 @@ } }, "node_modules/prettier-plugin-solidity": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.1.1.tgz", - "integrity": "sha512-uD24KO26tAHF+zMN2nt1OUzfknzza5AgxjogQQrMLZc7j8xiQrDoNWNeOlfFC0YLTwo12CLD10b9niLyP6AqXg==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.1.2.tgz", + "integrity": "sha512-KC5oNbFJfyBaFiO0kl56J6AXnDmr9tUlBV1iqo864x4KQrKYKaBZvW9jhT2oC0NHoNp7/GoMJNxqL8pp8k7C/g==", "dev": true, "dependencies": { - "@solidity-parser/parser": "^0.14.5", + "@solidity-parser/parser": "^0.15.0", "semver": "^7.3.8", "solidity-comments-extractor": "^0.0.7" }, @@ -11423,39 +10527,15 @@ "prettier": ">=2.3.0 || >=3.0.0-alpha.0" } }, - "node_modules/prettier-plugin-solidity/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/prettier-plugin-solidity/node_modules/@solidity-parser/parser": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.15.0.tgz", + "integrity": "sha512-5UFJJTzWi1hgFk6aGCZ5rxG2DJkCJOzJ74qg7UkWSNCDSigW+CJLoYUb5bLiKrtI34Nr9rpFSUNHfkqtlL+N/w==", "dev": true, "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" + "antlr4ts": "^0.5.0-alpha.4" } }, - "node_modules/prettier-plugin-solidity/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/prettier-plugin-solidity/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -11471,15 +10551,6 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/promise": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", @@ -11525,20 +10596,6 @@ "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", "dev": true }, - "node_modules/public-encrypt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", - "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", - "dev": true, - "dependencies": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, "node_modules/pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -11624,15 +10681,12 @@ ] }, "node_modules/quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", "dev": true, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, "node_modules/randombytes": { @@ -11644,16 +10698,6 @@ "safe-buffer": "^5.1.0" } }, - "node_modules/randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "dev": true, - "dependencies": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -11664,9 +10708,9 @@ } }, "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dev": true, "dependencies": { "bytes": "3.1.2", @@ -11679,78 +10723,53 @@ } }, "node_modules/read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", "dev": true, "dependencies": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", "dev": true, "dependencies": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/read-pkg-up/node_modules/find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", - "dev": true, - "dependencies": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" + "node": ">=8" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/read-pkg-up/node_modules/path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", + "node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", "dev": true, - "dependencies": { - "pinkie-promise": "^2.0.0" - }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/read-pkg/node_modules/path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/read-pkg/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/read-yaml-file": { @@ -11768,19 +10787,10 @@ "node": ">=6" } }, - "node_modules/read-yaml-file/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.1.tgz", + "integrity": "sha512-+rQmrWMYGA90yenhTYsLWAsLsqVC8osOw6PKE1HDYiO0gdPeKe/xDHNzIAIn4C91YQ6oenEhfYqqc1883qHbjQ==", "dev": true, "dependencies": { "inherits": "^2.0.3", @@ -12047,12 +11057,12 @@ "dev": true }, "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/responselike": { @@ -12076,19 +11086,6 @@ "node": ">=8" } }, - "node_modules/restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", - "dev": true, - "dependencies": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", @@ -12180,15 +11177,6 @@ "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", "dev": true }, - "node_modules/run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -12241,18 +11229,6 @@ "integrity": "sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA==", "dev": true }, - "node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dev": true, - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" - } - }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -12755,46 +11731,64 @@ } }, "node_modules/slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, "dependencies": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" }, "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "color-convert": "^1.9.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/slice-ansi/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { - "color-name": "1.1.3" + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, "node_modules/slice-ansi/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/smartwrap": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/smartwrap/-/smartwrap-2.0.2.tgz", @@ -12824,13 +11818,19 @@ "node": ">=8" } }, - "node_modules/smartwrap/node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "node_modules/smartwrap/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">=6" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/smartwrap/node_modules/cliui": { @@ -12844,15 +11844,24 @@ "wrap-ansi": "^6.2.0" } }, - "node_modules/smartwrap/node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "node_modules/smartwrap/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, "engines": { - "node": ">=0.10.0" + "node": ">=7.0.0" } }, + "node_modules/smartwrap/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "node_modules/smartwrap/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -12930,19 +11939,6 @@ "node": ">=8" } }, - "node_modules/smartwrap/node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/snake-case": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-2.1.0.tgz", @@ -12997,11 +11993,15 @@ "wrap-ansi": "^2.0.0" } }, - "node_modules/solc/node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "node_modules/solc/node_modules/find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", "dev": true, + "dependencies": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, "engines": { "node": ">=0.10.0" } @@ -13066,6 +12066,68 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/solc/node_modules/path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", + "dev": true, + "dependencies": { + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/solc/node_modules/path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/solc/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/solc/node_modules/read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", + "dev": true, + "dependencies": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/solc/node_modules/read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", + "dev": true, + "dependencies": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/solc/node_modules/require-main-filename": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", @@ -13177,395 +12239,128 @@ } }, "node_modules/solhint": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/solhint/-/solhint-3.3.7.tgz", - "integrity": "sha512-NjjjVmXI3ehKkb3aNtRJWw55SUVJ8HMKKodwe0HnejA+k0d2kmhw7jvpa+MCTbcEgt8IWSwx0Hu6aCo/iYOZzQ==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/solhint/-/solhint-3.4.0.tgz", + "integrity": "sha512-FYEs/LoTxMsWFP/OGsEqR1CBDn3Bn7hrTWsgtjai17MzxITgearIdlo374KKZjjIycu8E2xBcJ+RSWeoBvQmkw==", "dev": true, "dependencies": { - "@solidity-parser/parser": "^0.14.1", - "ajv": "^6.6.1", - "antlr4": "4.7.1", - "ast-parents": "0.0.1", - "chalk": "^2.4.2", - "commander": "2.18.0", - "cosmiconfig": "^5.0.7", - "eslint": "^5.6.0", - "fast-diff": "^1.1.2", - "glob": "^7.1.3", - "ignore": "^4.0.6", - "js-yaml": "^3.12.0", - "lodash": "^4.17.11", - "semver": "^6.3.0" + "@solidity-parser/parser": "^0.15.0", + "ajv": "^6.12.6", + "antlr4": "^4.11.0", + "ast-parents": "^0.0.1", + "chalk": "^4.1.2", + "commander": "^10.0.0", + "cosmiconfig": "^8.0.0", + "fast-diff": "^1.2.0", + "glob": "^8.0.3", + "ignore": "^5.2.4", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "pluralize": "^8.0.0", + "semver": "^6.3.0", + "strip-ansi": "^6.0.1", + "table": "^6.8.1", + "text-table": "^0.2.0" }, "bin": { "solhint": "solhint.js" }, "optionalDependencies": { - "prettier": "^1.14.3" + "prettier": "^2.8.3" } }, - "node_modules/solhint/node_modules/acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "node_modules/solhint/node_modules/@solidity-parser/parser": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.15.0.tgz", + "integrity": "sha512-5UFJJTzWi1hgFk6aGCZ5rxG2DJkCJOzJ74qg7UkWSNCDSigW+CJLoYUb5bLiKrtI34Nr9rpFSUNHfkqtlL+N/w==", + "dev": true, + "dependencies": { + "antlr4ts": "^0.5.0-alpha.4" + } + }, + "node_modules/solhint/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, - "bin": { - "acorn": "bin/acorn" - }, "engines": { - "node": ">=0.4.0" + "node": ">=8" } }, "node_modules/solhint/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "color-convert": "^1.9.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/solhint/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "node_modules/solhint/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, "node_modules/solhint/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { - "color-name": "1.1.3" + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, "node_modules/solhint/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/solhint/node_modules/cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "engines": { - "node": ">=4.8" - } - }, - "node_modules/solhint/node_modules/cross-spawn/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/solhint/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/solhint/node_modules/eslint": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz", - "integrity": "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.9.1", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "eslint-scope": "^4.0.3", - "eslint-utils": "^1.3.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^5.0.1", - "esquery": "^1.0.1", - "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", - "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", - "globals": "^11.7.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "inquirer": "^6.2.2", - "js-yaml": "^3.13.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.11", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", - "progress": "^2.0.0", - "regexpp": "^2.0.1", - "semver": "^5.5.1", - "strip-ansi": "^4.0.0", - "strip-json-comments": "^2.0.1", - "table": "^5.2.3", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^6.14.0 || ^8.10.0 || >=9.10.0" - } - }, - "node_modules/solhint/node_modules/eslint-scope": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", - "dev": true, - "dependencies": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/solhint/node_modules/eslint-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", - "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/solhint/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/solhint/node_modules/eslint/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/solhint/node_modules/espree": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", - "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", - "dev": true, - "dependencies": { - "acorn": "^6.0.7", - "acorn-jsx": "^5.0.0", - "eslint-visitor-keys": "^1.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/solhint/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/solhint/node_modules/file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", - "dev": true, - "dependencies": { - "flat-cache": "^2.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/solhint/node_modules/flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", - "dev": true, - "dependencies": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/solhint/node_modules/flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", - "dev": true - }, - "node_modules/solhint/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/solhint/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/solhint/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/solhint/node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/solhint/node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "node_modules/solhint/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/solhint/node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/solhint/node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/solhint/node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/solhint/node_modules/prettier": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", - "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", - "dev": true, - "optional": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/solhint/node_modules/regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", - "dev": true, - "engines": { - "node": ">=6.5.0" - } - }, - "node_modules/solhint/node_modules/rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" + "argparse": "^2.0.1" }, "bin": { - "rimraf": "bin.js" + "js-yaml": "bin/js-yaml.js" } }, "node_modules/solhint/node_modules/semver": { @@ -13577,76 +12372,34 @@ "semver": "bin/semver.js" } }, - "node_modules/solhint/node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "node_modules/solhint/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "dependencies": { - "shebang-regex": "^1.0.0" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/solhint/node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/solhint/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/solhint/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=4" - } - }, - "node_modules/solhint/node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/solhint/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" + "node": ">=8" } }, "node_modules/solidity-ast": { - "version": "0.4.40", - "resolved": "https://registry.npmjs.org/solidity-ast/-/solidity-ast-0.4.40.tgz", - "integrity": "sha512-M8uLBT2jgFB7B0iVAC5a2l71J8vim7aEm03AZkaHbDqyrl1pE+i5PriMEw6WlwGfHp3/Ym7cn9BqvVLQgRk+Yw==", + "version": "0.4.46", + "resolved": "https://registry.npmjs.org/solidity-ast/-/solidity-ast-0.4.46.tgz", + "integrity": "sha512-MlPZQfPhjWXqh7YxWcBGDXaPZIfMYCOHYoLEhGDWulNwEPIQQZuB7mA9eP17CU0jY/bGR4avCEUVVpvHtT2gbA==", "dev": true }, "node_modules/solidity-comments": { @@ -13888,18 +12641,6 @@ "node": ">=6" } }, - "node_modules/solidity-coverage/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/solidity-coverage/node_modules/camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", @@ -13909,20 +12650,6 @@ "node": ">=6" } }, - "node_modules/solidity-coverage/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/solidity-coverage/node_modules/chokidar": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", @@ -13955,21 +12682,6 @@ "wrap-ansi": "^5.1.0" } }, - "node_modules/solidity-coverage/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/solidity-coverage/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, "node_modules/solidity-coverage/node_modules/debug": { "version": "3.2.6", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", @@ -13980,15 +12692,6 @@ "ms": "^2.1.1" } }, - "node_modules/solidity-coverage/node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/solidity-coverage/node_modules/diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", @@ -14004,15 +12707,6 @@ "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "dev": true }, - "node_modules/solidity-coverage/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/solidity-coverage/node_modules/find-up": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", @@ -14067,29 +12761,42 @@ } }, "node_modules/solidity-coverage/node_modules/glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" }, "engines": { "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/solidity-coverage/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "node_modules/solidity-coverage/node_modules/globby": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz", + "integrity": "sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==", "dev": true, + "dependencies": { + "@types/glob": "^7.1.1", + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.0.3", + "glob": "^7.1.3", + "ignore": "^5.1.1", + "merge2": "^1.2.3", + "slash": "^3.0.0" + }, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/solidity-coverage/node_modules/js-yaml": { @@ -14130,18 +12837,6 @@ "node": ">=8" } }, - "node_modules/solidity-coverage/node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/solidity-coverage/node_modules/mkdirp": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", @@ -14197,16 +12892,33 @@ "url": "https://opencollective.com/mochajs" } }, - "node_modules/solidity-coverage/node_modules/mocha/node_modules/supports-color": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", - "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "node_modules/solidity-coverage/node_modules/mocha/node_modules/glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "dev": true, "dependencies": { - "has-flag": "^3.0.0" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" }, "engines": { - "node": ">=6" + "node": "*" + } + }, + "node_modules/solidity-coverage/node_modules/mocha/node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, "node_modules/solidity-coverage/node_modules/ms": { @@ -14215,6 +12927,21 @@ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", "dev": true }, + "node_modules/solidity-coverage/node_modules/object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/solidity-coverage/node_modules/p-locate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", @@ -14284,15 +13011,15 @@ } }, "node_modules/solidity-coverage/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "dev": true, "dependencies": { "has-flag": "^3.0.0" }, "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/solidity-coverage/node_modules/which": { @@ -14682,15 +13409,12 @@ } }, "node_modules/strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, - "dependencies": { - "is-utf8": "^0.2.0" - }, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, "node_modules/strip-hex-prefix": { @@ -14728,15 +13452,15 @@ } }, "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "has-flag": "^3.0.0" }, "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/swap-case": { @@ -14856,6 +13580,18 @@ "node": ">=8" } }, + "node_modules/swarm-js/node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/sync-request": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-6.1.0.tgz", @@ -14880,59 +13616,94 @@ } }, "node_modules/table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", + "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", "dev": true, "dependencies": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=6.0.0" + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, "node_modules/table/node_modules/ansi-regex": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", - "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/table/node_modules/emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "node_modules/table/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true }, + "node_modules/table/node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/table/node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=6" + "node": ">=8" } }, "node_modules/table/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "dependencies": { - "ansi-regex": "^4.1.0" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=6" + "node": ">=8" } }, "node_modules/tar": { @@ -15006,12 +13777,6 @@ "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==", "dev": true }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true - }, "node_modules/timed-out": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", @@ -15078,9 +13843,9 @@ } }, "node_modules/tough-cookie/node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", "dev": true, "engines": { "node": ">=6" @@ -15152,6 +13917,21 @@ "node": ">=8" } }, + "node_modules/tty-table/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/tty-table/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -15168,6 +13948,33 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/tty-table/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/tty-table/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/tty-table/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/tty-table/node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -15180,6 +13987,18 @@ "node": ">=8" } }, + "node_modules/tty-table/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -15256,6 +14075,20 @@ "node": ">= 0.6" } }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", @@ -15312,9 +14145,9 @@ "dev": true }, "node_modules/undici": { - "version": "5.14.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.14.0.tgz", - "integrity": "sha512-yJlHYw6yXPPsuOH0x2Ib1Km61vu4hLiRRQoafs+WUgX1vO64vgnxiCEN9dpIrhZyHFsai3F0AEj4P9zy19enEQ==", + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.20.0.tgz", + "integrity": "sha512-J3j60dYzuo6Eevbawwp1sdg16k5Tf768bxYK4TUJRH7cBM4kFCbf3mOnM/0E3vQYXvpxITbbWmBafaDbxLDz3g==", "dev": true, "dependencies": { "busboy": "^1.6.0" @@ -15476,28 +14309,28 @@ } }, "node_modules/web3": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3/-/web3-1.8.1.tgz", - "integrity": "sha512-tAqFsQhGv340C9OgRJIuoScN7f7wa1tUvsnnDUMt9YE6J4gcm7TV2Uwv+KERnzvV+xgdeuULYpsioRRNKrUvoQ==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.8.2.tgz", + "integrity": "sha512-92h0GdEHW9wqDICQQKyG4foZBYi0OQkyg4CRml2F7XBl/NG+fu9o6J19kzfFXzSBoA4DnJXbyRgj/RHZv5LRiw==", "dev": true, "hasInstallScript": true, "dependencies": { - "web3-bzz": "1.8.1", - "web3-core": "1.8.1", - "web3-eth": "1.8.1", - "web3-eth-personal": "1.8.1", - "web3-net": "1.8.1", - "web3-shh": "1.8.1", - "web3-utils": "1.8.1" + "web3-bzz": "1.8.2", + "web3-core": "1.8.2", + "web3-eth": "1.8.2", + "web3-eth-personal": "1.8.2", + "web3-net": "1.8.2", + "web3-shh": "1.8.2", + "web3-utils": "1.8.2" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-bzz": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.8.1.tgz", - "integrity": "sha512-dJJHS84nvpoxv6ijTMkdUSlRr5beCXNtx4UZcrFLHBva8dT63QEtKdLyDt2AyMJJdVzTCk78uir/6XtVWrdS6w==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.8.2.tgz", + "integrity": "sha512-1EEnxjPnFnvNWw3XeeKuTR8PBxYd0+XWzvaLK7OJC/Go9O8llLGxrxICbKV+8cgIE0sDRBxiYx02X+6OhoAQ9w==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -15509,63 +14342,57 @@ "node": ">=8.0.0" } }, - "node_modules/web3-bzz/node_modules/@types/node": { - "version": "12.20.55", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", - "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", - "dev": true - }, "node_modules/web3-core": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.8.1.tgz", - "integrity": "sha512-LbRZlJH2N6nS3n3Eo9Y++25IvzMY7WvYnp4NM/Ajhh97dAdglYs6rToQ2DbL2RLvTYmTew4O/y9WmOk4nq9COw==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.8.2.tgz", + "integrity": "sha512-DJTVEAYcNqxkqruJE+Rxp3CIv0y5AZMwPHQmOkz/cz+MM75SIzMTc0AUdXzGyTS8xMF8h3YWMQGgGEy8SBf1PQ==", "dev": true, "dependencies": { "@types/bn.js": "^5.1.0", "@types/node": "^12.12.6", "bignumber.js": "^9.0.0", - "web3-core-helpers": "1.8.1", - "web3-core-method": "1.8.1", - "web3-core-requestmanager": "1.8.1", - "web3-utils": "1.8.1" + "web3-core-helpers": "1.8.2", + "web3-core-method": "1.8.2", + "web3-core-requestmanager": "1.8.2", + "web3-utils": "1.8.2" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-core-helpers": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.8.1.tgz", - "integrity": "sha512-ClzNO6T1S1gifC+BThw0+GTfcsjLEY8T1qUp6Ly2+w4PntAdNtKahxWKApWJ0l9idqot/fFIDXwO3Euu7I0Xqw==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.8.2.tgz", + "integrity": "sha512-6B1eLlq9JFrfealZBomd1fmlq1o4A09vrCVQSa51ANoib/jllT3atZrRDr0zt1rfI7TSZTZBXdN/aTdeN99DWw==", "dev": true, "dependencies": { - "web3-eth-iban": "1.8.1", - "web3-utils": "1.8.1" + "web3-eth-iban": "1.8.2", + "web3-utils": "1.8.2" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-core-method": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.8.1.tgz", - "integrity": "sha512-oYGRodktfs86NrnFwaWTbv2S38JnpPslFwSSARwFv4W9cjbGUW3LDeA5MKD/dRY+ssZ5OaekeMsUCLoGhX68yA==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.8.2.tgz", + "integrity": "sha512-1qnr5mw5wVyULzLOrk4B+ryO3gfGjGd/fx8NR+J2xCGLf1e6OSjxT9vbfuQ3fErk/NjSTWWreieYWLMhaogcRA==", "dev": true, "dependencies": { "@ethersproject/transactions": "^5.6.2", - "web3-core-helpers": "1.8.1", - "web3-core-promievent": "1.8.1", - "web3-core-subscriptions": "1.8.1", - "web3-utils": "1.8.1" + "web3-core-helpers": "1.8.2", + "web3-core-promievent": "1.8.2", + "web3-core-subscriptions": "1.8.2", + "web3-utils": "1.8.2" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-core-promievent": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.8.1.tgz", - "integrity": "sha512-9mxqHlgB0MrZI4oUIRFkuoJMNj3E7btjrMv3sMer/Z9rYR1PfoSc1aAokw4rxKIcAh+ylVtd/acaB2HKB7aRPg==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.8.2.tgz", + "integrity": "sha512-nvkJWDVgoOSsolJldN33tKW6bKKRJX3MCPDYMwP5SUFOA/mCzDEoI88N0JFofDTXkh1k7gOqp1pvwi9heuaxGg==", "dev": true, "dependencies": { "eventemitter3": "4.0.4" @@ -15575,40 +14402,34 @@ } }, "node_modules/web3-core-requestmanager": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.8.1.tgz", - "integrity": "sha512-x+VC2YPPwZ1khvqA6TA69LvfFCOZXsoUVOxmTx/vIN22PrY9KzKhxcE7pBSiGhmab1jtmRYXUbcQSVpAXqL8cw==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.8.2.tgz", + "integrity": "sha512-p1d090RYs5Mu7DK1yyc3GCBVZB/03rBtFhYFoS2EruGzOWs/5Q0grgtpwS/DScdRAm8wB8mYEBhY/RKJWF6B2g==", "dev": true, "dependencies": { - "util": "^0.12.0", - "web3-core-helpers": "1.8.1", - "web3-providers-http": "1.8.1", - "web3-providers-ipc": "1.8.1", - "web3-providers-ws": "1.8.1" + "util": "^0.12.5", + "web3-core-helpers": "1.8.2", + "web3-providers-http": "1.8.2", + "web3-providers-ipc": "1.8.2", + "web3-providers-ws": "1.8.2" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-core-subscriptions": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.8.1.tgz", - "integrity": "sha512-bmCMq5OeA3E2vZUh8Js1HcJbhwtsE+yeMqGC4oIZB3XsL5SLqyKLB/pU+qUYqQ9o4GdcrFTDPhPg1bgvf7p1Pw==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.8.2.tgz", + "integrity": "sha512-vXQogHDmAIQcKpXvGiMddBUeP9lnKgYF64+yQJhPNE5PnWr1sAibXuIPV7mIPihpFr/n/DORRj6Wh1pUv9zaTw==", "dev": true, "dependencies": { "eventemitter3": "4.0.4", - "web3-core-helpers": "1.8.1" + "web3-core-helpers": "1.8.2" }, "engines": { "node": ">=8.0.0" } }, - "node_modules/web3-core/node_modules/@types/node": { - "version": "12.20.55", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", - "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", - "dev": true - }, "node_modules/web3-core/node_modules/bignumber.js": { "version": "9.1.1", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz", @@ -15619,58 +14440,57 @@ } }, "node_modules/web3-eth": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.8.1.tgz", - "integrity": "sha512-LgyzbhFqiFRd8M8sBXoFN4ztzOnkeckl3H/9lH5ek7AdoRMhBg7tYpYRP3E5qkhd/q+yiZmcUgy1AF6NHrC1wg==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.8.2.tgz", + "integrity": "sha512-JoTiWWc4F4TInpbvDUGb0WgDYJsFhuIjJlinc5ByjWD88Gvh+GKLsRjjFdbqe5YtwIGT4NymwoC5LQd1K6u/QQ==", "dev": true, "dependencies": { - "web3-core": "1.8.1", - "web3-core-helpers": "1.8.1", - "web3-core-method": "1.8.1", - "web3-core-subscriptions": "1.8.1", - "web3-eth-abi": "1.8.1", - "web3-eth-accounts": "1.8.1", - "web3-eth-contract": "1.8.1", - "web3-eth-ens": "1.8.1", - "web3-eth-iban": "1.8.1", - "web3-eth-personal": "1.8.1", - "web3-net": "1.8.1", - "web3-utils": "1.8.1" + "web3-core": "1.8.2", + "web3-core-helpers": "1.8.2", + "web3-core-method": "1.8.2", + "web3-core-subscriptions": "1.8.2", + "web3-eth-abi": "1.8.2", + "web3-eth-accounts": "1.8.2", + "web3-eth-contract": "1.8.2", + "web3-eth-ens": "1.8.2", + "web3-eth-iban": "1.8.2", + "web3-eth-personal": "1.8.2", + "web3-net": "1.8.2", + "web3-utils": "1.8.2" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-eth-abi": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.8.1.tgz", - "integrity": "sha512-0mZvCRTIG0UhDhJwNQJgJxu4b4DyIpuMA0GTfqxqeuqzX4Q/ZvmoNurw0ExTfXaGPP82UUmmdkRi6FdZOx+C6w==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.8.2.tgz", + "integrity": "sha512-Om9g3kaRNjqiNPAgKwGT16y+ZwtBzRe4ZJFGjLiSs6v5I7TPNF+rRMWuKnR6jq0azQZDj6rblvKFMA49/k48Og==", "dev": true, "dependencies": { "@ethersproject/abi": "^5.6.3", - "web3-utils": "1.8.1" + "web3-utils": "1.8.2" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-eth-accounts": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.8.1.tgz", - "integrity": "sha512-mgzxSYgN54/NsOFBO1Fq1KkXp1S5KlBvI/DlgvajU72rupoFMq6Cu6Yp9GUaZ/w2ij9PzEJuFJk174XwtfMCmg==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.8.2.tgz", + "integrity": "sha512-c367Ij63VCz9YdyjiHHWLFtN85l6QghgwMQH2B1eM/p9Y5lTlTX7t/Eg/8+f1yoIStXbk2w/PYM2lk+IkbqdLA==", "dev": true, "dependencies": { "@ethereumjs/common": "2.5.0", "@ethereumjs/tx": "3.3.2", - "crypto-browserify": "3.12.0", "eth-lib": "0.2.8", - "ethereumjs-util": "^7.0.10", + "ethereumjs-util": "^7.1.5", "scrypt-js": "^3.0.1", "uuid": "^9.0.0", - "web3-core": "1.8.1", - "web3-core-helpers": "1.8.1", - "web3-core-method": "1.8.1", - "web3-utils": "1.8.1" + "web3-core": "1.8.2", + "web3-core-helpers": "1.8.2", + "web3-core-method": "1.8.2", + "web3-utils": "1.8.2" }, "engines": { "node": ">=8.0.0" @@ -15697,51 +14517,51 @@ } }, "node_modules/web3-eth-contract": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.8.1.tgz", - "integrity": "sha512-1wphnl+/xwCE2io44JKnN+ti3oa47BKRiVzvWd42icwRbcpFfRxH9QH+aQX3u8VZIISNH7dAkTWpGIIJgGFTmg==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.8.2.tgz", + "integrity": "sha512-ID5A25tHTSBNwOPjiXSVzxruz006ULRIDbzWTYIFTp7NJ7vXu/kynKK2ag/ObuTqBpMbobP8nXcA9b5EDkIdQA==", "dev": true, "dependencies": { "@types/bn.js": "^5.1.0", - "web3-core": "1.8.1", - "web3-core-helpers": "1.8.1", - "web3-core-method": "1.8.1", - "web3-core-promievent": "1.8.1", - "web3-core-subscriptions": "1.8.1", - "web3-eth-abi": "1.8.1", - "web3-utils": "1.8.1" + "web3-core": "1.8.2", + "web3-core-helpers": "1.8.2", + "web3-core-method": "1.8.2", + "web3-core-promievent": "1.8.2", + "web3-core-subscriptions": "1.8.2", + "web3-eth-abi": "1.8.2", + "web3-utils": "1.8.2" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-eth-ens": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.8.1.tgz", - "integrity": "sha512-FT8xTI9uN8RxeBQa/W8pLa2aoFh4+EE34w7W2271LICKzla1dtLyb6XSdn48vsUcPmhWsTVk9mO9RTU0l4LGQQ==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.8.2.tgz", + "integrity": "sha512-PWph7C/CnqdWuu1+SH4U4zdrK4t2HNt0I4XzPYFdv9ugE8EuojselioPQXsVGvjql+Nt3jDLvQvggPqlMbvwRw==", "dev": true, "dependencies": { "content-hash": "^2.5.2", "eth-ens-namehash": "2.0.8", - "web3-core": "1.8.1", - "web3-core-helpers": "1.8.1", - "web3-core-promievent": "1.8.1", - "web3-eth-abi": "1.8.1", - "web3-eth-contract": "1.8.1", - "web3-utils": "1.8.1" + "web3-core": "1.8.2", + "web3-core-helpers": "1.8.2", + "web3-core-promievent": "1.8.2", + "web3-eth-abi": "1.8.2", + "web3-eth-contract": "1.8.2", + "web3-utils": "1.8.2" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-eth-iban": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.8.1.tgz", - "integrity": "sha512-DomoQBfvIdtM08RyMGkMVBOH0vpOIxSSQ+jukWk/EkMLGMWJtXw/K2c2uHAeq3L/VPWNB7zXV2DUEGV/lNE2Dg==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.8.2.tgz", + "integrity": "sha512-h3vNblDWkWMuYx93Q27TAJz6lhzpP93EiC3+45D6xoz983p6si773vntoQ+H+5aZhwglBtoiBzdh7PSSOnP/xQ==", "dev": true, "dependencies": { "bn.js": "^5.2.1", - "web3-utils": "1.8.1" + "web3-utils": "1.8.2" }, "engines": { "node": ">=8.0.0" @@ -15754,78 +14574,72 @@ "dev": true }, "node_modules/web3-eth-personal": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.8.1.tgz", - "integrity": "sha512-myIYMvj7SDIoV9vE5BkVdon3pya1WinaXItugoii2VoTcQNPOtBxmYVH+XS5ErzCJlnxzphpQrkywyY64bbbCA==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.8.2.tgz", + "integrity": "sha512-Vg4HfwCr7doiUF/RC+Jz0wT4+cYaXcOWMAW2AHIjHX6Z7Xwa8nrURIeQgeEE62qcEHAzajyAdB1u6bJyTfuCXw==", "dev": true, "dependencies": { "@types/node": "^12.12.6", - "web3-core": "1.8.1", - "web3-core-helpers": "1.8.1", - "web3-core-method": "1.8.1", - "web3-net": "1.8.1", - "web3-utils": "1.8.1" + "web3-core": "1.8.2", + "web3-core-helpers": "1.8.2", + "web3-core-method": "1.8.2", + "web3-net": "1.8.2", + "web3-utils": "1.8.2" }, "engines": { "node": ">=8.0.0" } }, - "node_modules/web3-eth-personal/node_modules/@types/node": { - "version": "12.20.55", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", - "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", - "dev": true - }, "node_modules/web3-net": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.8.1.tgz", - "integrity": "sha512-LyEJAwogdFo0UAXZqoSJGFjopdt+kLw0P00FSZn2yszbgcoI7EwC+nXiOsEe12xz4LqpYLOtbR7+gxgiTVjjHQ==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.8.2.tgz", + "integrity": "sha512-1itkDMGmbgb83Dg9nporFes9/fxsU7smJ3oRXlFkg4ZHn8YJyP1MSQFPJWWwSc+GrcCFt4O5IrUTvEkHqE3xag==", "dev": true, "dependencies": { - "web3-core": "1.8.1", - "web3-core-method": "1.8.1", - "web3-utils": "1.8.1" + "web3-core": "1.8.2", + "web3-core-method": "1.8.2", + "web3-utils": "1.8.2" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-providers-http": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.8.1.tgz", - "integrity": "sha512-1Zyts4O9W/UNEPkp+jyL19Jc3D15S4yp8xuLTjVhcUEAlHo24NDWEKxtZGUuHk4HrKL2gp8OlsDbJ7MM+ESDgg==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.8.2.tgz", + "integrity": "sha512-2xY94IIEQd16+b+vIBF4IC1p7GVaz9q4EUFscvMUjtEq4ru4Atdzjs9GP+jmcoo49p70II0UV3bqQcz0TQfVyQ==", "dev": true, "dependencies": { "abortcontroller-polyfill": "^1.7.3", "cross-fetch": "^3.1.4", "es6-promise": "^4.2.8", - "web3-core-helpers": "1.8.1" + "web3-core-helpers": "1.8.2" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-providers-ipc": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.8.1.tgz", - "integrity": "sha512-nw/W5nclvi+P2z2dYkLWReKLnocStflWqFl+qjtv0xn3MrUTyXMzSF0+61i77+16xFsTgzo4wS/NWIOVkR0EFA==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.8.2.tgz", + "integrity": "sha512-p6fqKVGFg+WiXGHWnB1hu43PbvPkDHTz4RgoEzbXugv5rtv5zfYLqm8Ba6lrJOS5ks9kGKR21a0y3NzE3u7V4w==", "dev": true, "dependencies": { "oboe": "2.1.5", - "web3-core-helpers": "1.8.1" + "web3-core-helpers": "1.8.2" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-providers-ws": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.8.1.tgz", - "integrity": "sha512-TNefIDAMpdx57+YdWpYZ/xdofS0P+FfKaDYXhn24ie/tH9G+AB+UBSOKnjN0KSadcRSCMBwGPRiEmNHPavZdsA==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.8.2.tgz", + "integrity": "sha512-3s/4K+wHgbiN+Zrp9YjMq2eqAF6QGABw7wFftPdx+m5hWImV27/MoIx57c6HffNRqZXmCHnfWWFCNHHsi7wXnA==", "dev": true, "dependencies": { "eventemitter3": "4.0.4", - "web3-core-helpers": "1.8.1", + "web3-core-helpers": "1.8.2", "websocket": "^1.0.32" }, "engines": { @@ -15833,25 +14647,25 @@ } }, "node_modules/web3-shh": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.8.1.tgz", - "integrity": "sha512-sqHgarnfcY2Qt3PYS4R6YveHrDy7hmL09yeLLHHCI+RKirmjLVqV0rc5LJWUtlbYI+kDoa5gbgde489M9ZAC0g==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.8.2.tgz", + "integrity": "sha512-uZ+3MAoNcaJsXXNCDnizKJ5viBNeHOFYsCbFhV755Uu52FswzTOw6DtE7yK9nYXMtIhiSgi7nwl1RYzP8pystw==", "dev": true, "hasInstallScript": true, "dependencies": { - "web3-core": "1.8.1", - "web3-core-method": "1.8.1", - "web3-core-subscriptions": "1.8.1", - "web3-net": "1.8.1" + "web3-core": "1.8.2", + "web3-core-method": "1.8.2", + "web3-core-subscriptions": "1.8.2", + "web3-net": "1.8.2" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-utils": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.8.1.tgz", - "integrity": "sha512-LgnM9p6V7rHHUGfpMZod+NST8cRfGzJ1BTXAyNo7A9cJX9LczBfSRxJp+U/GInYe9mby40t3v22AJdlELibnsQ==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.8.2.tgz", + "integrity": "sha512-v7j6xhfLQfY7xQDrUP0BKbaNrmZ2/+egbqP9q3KYmOiPpnvAfol+32slgL0WX/5n8VPvKCK5EZ1HGrAVICSToA==", "dev": true, "dependencies": { "bn.js": "^5.2.1", @@ -16058,6 +14872,39 @@ "node": ">=8" } }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -16099,18 +14946,6 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, - "node_modules/write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", - "dev": true, - "dependencies": { - "mkdirp": "^0.5.1" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/ws": { "version": "7.5.9", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", @@ -16211,9 +15046,9 @@ "dev": true }, "node_modules/yargs": { - "version": "17.6.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", - "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", "dev": true, "dependencies": { "cliui": "^8.0.1", @@ -16229,12 +15064,25 @@ } }, "node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs-parser/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, "engines": { - "node": ">=10" + "node": ">=6" } }, "node_modules/yargs-unparser": { @@ -16264,6 +15112,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/yargs-unparser/node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yargs-unparser/node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/yargs/node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -16355,70 +15224,12 @@ "@babel/helper-validator-identifier": "^7.18.6", "chalk": "^2.0.0", "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } } }, "@babel/runtime": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.7.tgz", - "integrity": "sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", + "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", "dev": true, "requires": { "regenerator-runtime": "^0.13.11" @@ -16445,18 +15256,6 @@ "semver": "^5.4.1" }, "dependencies": { - "detect-indent": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", - "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", - "dev": true - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -16548,79 +15347,11 @@ "tty-table": "^4.1.5" }, "dependencies": { - "ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } } } }, @@ -16661,67 +15392,11 @@ "semver": "^5.4.1" }, "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } } } }, @@ -16778,64 +15453,6 @@ "dev": true, "requires": { "chalk": "^2.1.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } } }, "@changesets/parse": { @@ -16875,64 +15492,6 @@ "chalk": "^2.1.0", "fs-extra": "^7.0.1", "p-filter": "^2.1.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } } }, "@changesets/types": { @@ -17573,12 +16132,6 @@ "fs-extra": "^8.1.0" }, "dependencies": { - "@types/node": { - "version": "12.20.55", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", - "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", - "dev": true - }, "fs-extra": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", @@ -17622,20 +16175,6 @@ "jsonfile": "^4.0.0", "universalify": "^0.1.0" } - }, - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - } } } }, @@ -17679,15 +16218,15 @@ } }, "@noble/hashes": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.1.2.tgz", - "integrity": "sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", + "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==", "dev": true }, "@noble/secp256k1": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.6.3.tgz", - "integrity": "sha512-T04e4iTurVy7I8Sw4+c5OSN9/RkPlo1uKxAomtxQNLq8j1uPAqnsqG1bqvY3Jv7c13gyr6dui0zmh/I3+f/JaQ==", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", "dev": true }, "@nodelib/fs.scandir": { @@ -17870,9 +16409,9 @@ } }, "@nomicfoundation/hardhat-network-helpers": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.0.7.tgz", - "integrity": "sha512-X+3mNvn8B7BY5hpIaLO+TrfzWq12bpux+ajGGdmdcfC78NXmYmOZkAtiz1QZx1YIZGMS1LaXzPXyBExxKFpCaw==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.0.8.tgz", + "integrity": "sha512-MNqQbzUJZnCMIYvlniC3U+kcavz/PhhQSsY90tbEtUyMj/IQqsLwIRZa4ctjABh3Bz0KCh9OXUZ7Yk/d9hr45Q==", "dev": true, "requires": { "ethereumjs-util": "^7.1.4" @@ -18044,6 +16583,57 @@ "js-yaml": "^3.13.1", "lodash.startcase": "^4.4.0", "minimist": "^1.2.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "@openzeppelin/test-helpers": { @@ -18064,6 +16654,12 @@ "web3-utils": "^1.2.5" }, "dependencies": { + "ansi-colors": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", + "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", + "dev": true + }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -18073,9 +16669,9 @@ } }, "@openzeppelin/upgrades-core": { - "version": "1.20.6", - "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades-core/-/upgrades-core-1.20.6.tgz", - "integrity": "sha512-KWdtlahm+iunlAlzLsdpBueanwEx0LLPfAkDL1p0C4SPjMiUqHHFlyGtmmWwdiqDpJ//605vfwkd5RqfnFrHSg==", + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades-core/-/upgrades-core-1.24.0.tgz", + "integrity": "sha512-lXf1tUrCZ3Q/YmWhw0cuSSOHMp0OAsmeOg1fhSGEM6nQQ6cIVlFvq2pCV5hZMb7xkOm5pmmzV8JW1W3kfW6Lfw==", "dev": true, "requires": { "cbor": "^8.0.0", @@ -18087,13 +16683,13 @@ "solidity-ast": "^0.4.15" }, "dependencies": { - "cbor": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/cbor/-/cbor-8.1.0.tgz", - "integrity": "sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==", + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "nofilter": "^3.1.0" + "color-convert": "^2.0.1" } }, "chalk": { @@ -18106,11 +16702,35 @@ "supports-color": "^7.1.0" } }, - "nofilter": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz", - "integrity": "sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==", + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } } } }, @@ -18121,23 +16741,23 @@ "dev": true }, "@scure/bip32": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.0.tgz", - "integrity": "sha512-ftTW3kKX54YXLCxH6BB7oEEoJfoE2pIgw7MINKAs5PsS6nqKPuKk1haTF/EuHmYqG330t5GSrdmtRuHaY1a62Q==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz", + "integrity": "sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==", "dev": true, "requires": { - "@noble/hashes": "~1.1.1", - "@noble/secp256k1": "~1.6.0", + "@noble/hashes": "~1.2.0", + "@noble/secp256k1": "~1.7.0", "@scure/base": "~1.1.0" } }, "@scure/bip39": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.0.tgz", - "integrity": "sha512-pwrPOS16VeTKg98dYXQyIjJEcWfz7/1YJIwxUEPFfQPtc86Ym/1sVgQ2RLoD43AazMk2l/unK4ITySSpW2+82w==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz", + "integrity": "sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==", "dev": true, "requires": { - "@noble/hashes": "~1.1.1", + "@noble/hashes": "~1.2.0", "@scure/base": "~1.1.0" } }, @@ -18247,14 +16867,14 @@ } }, "@truffle/abi-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@truffle/abi-utils/-/abi-utils-0.3.6.tgz", - "integrity": "sha512-61aTH2QmwVA1INaPMufRHTsS6jsEhS+GCkuCDdvBDmwctSnCKGDOr185BGt65QrpMRxYmIoH6WFBSNMYxW9GRw==", + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@truffle/abi-utils/-/abi-utils-0.3.8.tgz", + "integrity": "sha512-RevMtlEuQw9cE2VWzQuvLDSYPCVSZQQUOsaK8ArcwxXct6ugiJCDC7tNouhHzP1Y4ccdZtG2y/XPHQJdzgYdZQ==", "dev": true, "requires": { "change-case": "3.0.2", "fast-check": "3.1.1", - "web3-utils": "1.8.1" + "web3-utils": "1.8.2" } }, "@truffle/blockchain-utils": { @@ -18264,13 +16884,13 @@ "dev": true }, "@truffle/codec": { - "version": "0.14.11", - "resolved": "https://registry.npmjs.org/@truffle/codec/-/codec-0.14.11.tgz", - "integrity": "sha512-NgfMNYemgMXqoEcJA5ZsEhxChCwq33rSxtNxlececEH/1Nf0r+ryfrfmLlyPmv8f3jorVf1GWa0zI0AedGCGYQ==", + "version": "0.14.15", + "resolved": "https://registry.npmjs.org/@truffle/codec/-/codec-0.14.15.tgz", + "integrity": "sha512-cooWy8blmvYQQRBKgzWJnDUS6mZE9cvnmpVN15jU6TseAQkBtmfYfCH12QCKEWMq2+R4yQICP54WNCYg78g72g==", "dev": true, "requires": { - "@truffle/abi-utils": "^0.3.6", - "@truffle/compile-common": "^0.9.1", + "@truffle/abi-utils": "^0.3.8", + "@truffle/compile-common": "^0.9.3", "big.js": "^6.0.3", "bn.js": "^5.1.3", "cbor": "^5.2.0", @@ -18278,15 +16898,31 @@ "lodash": "^4.17.21", "semver": "7.3.7", "utf8": "^3.0.0", - "web3-utils": "1.8.1" + "web3-utils": "1.8.2" }, "dependencies": { + "bignumber.js": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz", + "integrity": "sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig==", + "dev": true + }, "bn.js": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", "dev": true }, + "cbor": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/cbor/-/cbor-5.2.0.tgz", + "integrity": "sha512-5IMhi9e1QU76ppa5/ajP1BmMWZ2FHkhAhjeVKQ/EFCgYSEaeVaoGtL7cxJskf9oCCk+XjzaIdc3IuU/dbA/o2A==", + "dev": true, + "requires": { + "bignumber.js": "^9.0.1", + "nofilter": "^1.0.4" + } + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -18296,6 +16932,12 @@ "yallist": "^4.0.0" } }, + "nofilter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-1.0.4.tgz", + "integrity": "sha512-N8lidFp+fCz+TD51+haYdbDGrcBWwuHX40F5+z0qkUjMJ5Tp+rdSuAkMJ9N9eoolDlEVTf6u5icM+cNKkKW2mA==", + "dev": true + }, "semver": { "version": "7.3.7", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", @@ -18314,41 +16956,57 @@ } }, "@truffle/compile-common": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/@truffle/compile-common/-/compile-common-0.9.1.tgz", - "integrity": "sha512-mhdkX6ExZImHSBO3jGm6aAn8NpVtMTdjq50jRXY/O59/ZNC0J9WpRapxrAKUVNc+XydMdBlfeEpXoqTJg7cbXw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/@truffle/compile-common/-/compile-common-0.9.3.tgz", + "integrity": "sha512-9S86H5DRC0zEj164KeClP/6jVt1M/nRd7St89h6QbuIU0JjpqSz1SXpkvqhbFoV9hhW+4ZGh0NysjrdPlk7gFw==", "dev": true, "requires": { - "@truffle/error": "^0.1.1", + "@truffle/error": "^0.2.0", "colors": "1.4.0" + }, + "dependencies": { + "@truffle/error": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@truffle/error/-/error-0.2.0.tgz", + "integrity": "sha512-Fe0/z4WWb7IP2gBnv3l6zqP87Y0kSMs7oiSLakKJq17q3GUunrHSdioKuNspdggxkXIBhEQLhi8C+LJdwmHKWQ==", + "dev": true + } } }, "@truffle/contract": { - "version": "4.6.10", - "resolved": "https://registry.npmjs.org/@truffle/contract/-/contract-4.6.10.tgz", - "integrity": "sha512-69IZSXeQKRP3EutILqe+vLY5A5gUpeXUiZhm/Fy/qHHkP238vMjtOkTZGkY6bonYqmgk+vDY7KSYSYKzDNPdCA==", + "version": "4.6.15", + "resolved": "https://registry.npmjs.org/@truffle/contract/-/contract-4.6.15.tgz", + "integrity": "sha512-3V+50z94XRh+I3axz6Zrot1wlMhRiG2O9XjR20LwR5YBnzHV7YFfOs8x6pluXVLQyxcVJBISJyqxvGxpkecrZg==", "dev": true, "requires": { "@ensdomains/ensjs": "^2.1.0", "@truffle/blockchain-utils": "^0.1.6", - "@truffle/contract-schema": "^3.4.11", - "@truffle/debug-utils": "^6.0.42", - "@truffle/error": "^0.1.1", - "@truffle/interface-adapter": "^0.5.26", + "@truffle/contract-schema": "^3.4.12", + "@truffle/debug-utils": "^6.0.46", + "@truffle/error": "^0.2.0", + "@truffle/interface-adapter": "^0.5.29", "bignumber.js": "^7.2.1", "debug": "^4.3.1", "ethers": "^4.0.32", - "web3": "1.8.1", - "web3-core-helpers": "1.8.1", - "web3-core-promievent": "1.8.1", - "web3-eth-abi": "1.8.1", - "web3-utils": "1.8.1" + "web3": "1.8.2", + "web3-core-helpers": "1.8.2", + "web3-core-promievent": "1.8.2", + "web3-eth-abi": "1.8.2", + "web3-utils": "1.8.2" + }, + "dependencies": { + "@truffle/error": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@truffle/error/-/error-0.2.0.tgz", + "integrity": "sha512-Fe0/z4WWb7IP2gBnv3l6zqP87Y0kSMs7oiSLakKJq17q3GUunrHSdioKuNspdggxkXIBhEQLhi8C+LJdwmHKWQ==", + "dev": true + } } }, "@truffle/contract-schema": { - "version": "3.4.11", - "resolved": "https://registry.npmjs.org/@truffle/contract-schema/-/contract-schema-3.4.11.tgz", - "integrity": "sha512-wReyVZUPyU9Zy5PSCugBLG1nnruBmRAJ/gmoirQiJ9N2n+s1iGBTY49tkDqFMz3XUUE0kplfdb9YKZJlLkTWzQ==", + "version": "3.4.12", + "resolved": "https://registry.npmjs.org/@truffle/contract-schema/-/contract-schema-3.4.12.tgz", + "integrity": "sha512-XpMMps/bqHwiRuCyLiEEGWEAvGGzGj4u1X1+lzxrtIsrwbQhSZcdgEbXl9vGxOOJWOup3HXRCIsjlao27kS4OA==", "dev": true, "requires": { "ajv": "^6.10.0", @@ -18356,80 +17014,24 @@ } }, "@truffle/debug-utils": { - "version": "6.0.42", - "resolved": "https://registry.npmjs.org/@truffle/debug-utils/-/debug-utils-6.0.42.tgz", - "integrity": "sha512-9v70tj+My0Z2UZJ9OsuUlfo4Dt2AJqAQa/YWtGe28H8zsi+o9Dca0RsKWecuprdllgzrEs7ad8QUtSINhwjIlg==", + "version": "6.0.46", + "resolved": "https://registry.npmjs.org/@truffle/debug-utils/-/debug-utils-6.0.46.tgz", + "integrity": "sha512-MWko3c1M0NI8IT0yNh8Dh2xoDgR2R1apP8hc/9VsR/4Q7P6OE/578WRpZnvo2HWXYBiJ2PrWBDtMYBHntImrrA==", "dev": true, "requires": { - "@truffle/codec": "^0.14.11", + "@truffle/codec": "^0.14.15", "@trufflesuite/chromafi": "^3.0.0", "bn.js": "^5.1.3", "chalk": "^2.4.2", "debug": "^4.3.1", - "highlightjs-solidity": "^2.0.5" + "highlightjs-solidity": "^2.0.6" }, "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, "bn.js": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", "dev": true - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } } } }, @@ -18440,14 +17042,14 @@ "dev": true }, "@truffle/interface-adapter": { - "version": "0.5.26", - "resolved": "https://registry.npmjs.org/@truffle/interface-adapter/-/interface-adapter-0.5.26.tgz", - "integrity": "sha512-fBhoqtT+CT4XKXcOijvw0RIMgyUi3FJg+n5i5PyGBsoRzqbLZd9cZq+oMNjOZPdf3GH68hsOFOaQO5tZH7oZow==", + "version": "0.5.29", + "resolved": "https://registry.npmjs.org/@truffle/interface-adapter/-/interface-adapter-0.5.29.tgz", + "integrity": "sha512-6UlJ+f87z7y/dWk9UfbIU+4e80iRsp8h03LEiE5B+PvZbr6cuMjLJUBtBBQZMo3+xrIcS/2u3p5hOxW8OJm8tw==", "dev": true, "requires": { "bn.js": "^5.1.3", "ethers": "^4.0.32", - "web3": "1.8.1" + "web3": "1.8.2" }, "dependencies": { "bn.js": { @@ -18474,61 +17076,11 @@ "strip-indent": "^2.0.0" }, "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "detect-indent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz", + "integrity": "sha512-rlpvsxUtM0PQvy9iZe640/IWwWYyBsTApREbA1pHOpmOUIl9MkP/U4z7vTtg4Oaojvqhxt7sdufnT0EzGaR31g==", "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } } } }, @@ -18615,14 +17167,6 @@ "dev": true, "requires": { "ci-info": "^3.1.0" - }, - "dependencies": { - "ci-info": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.1.tgz", - "integrity": "sha512-4jYS4MOAaCIStSRwiuxc4B8MYhIe676yO1sYGzARnjXkWpmzZMMYxY6zu8WYWDhSuth5zhrQ1rhNSibyyvv4/w==", - "dev": true - } } }, "@types/keyv": { @@ -18653,9 +17197,9 @@ "dev": true }, "@types/node": { - "version": "18.11.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz", - "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==", + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", "dev": true }, "@types/normalize-package-data": { @@ -18762,9 +17306,9 @@ } }, "acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", "dev": true }, "acorn-jsx": { @@ -18831,9 +17375,9 @@ "optional": true }, "ansi-colors": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", - "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true }, "ansi-escapes": { @@ -18860,18 +17404,18 @@ "dev": true }, "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "color-convert": "^2.0.1" + "color-convert": "^1.9.0" } }, "antlr4": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.7.1.tgz", - "integrity": "sha512-haHyTW7Y9joE5MVs37P2lNYfU2RWBLfcRDD8OWldcdZm5TiCE91B5Xl1oWSwiDUSd4rlExpt2pu1fksYQjRBYQ==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.12.0.tgz", + "integrity": "sha512-23iB5IzXJZRZeK9TigzUyrNc9pSmNqAerJRBcNq1ETrmttMWRgaYZzC561IgEO3ygKsDJTYDTozABXa4b/fTQQ==", "dev": true }, "antlr4ts": { @@ -18963,18 +17507,6 @@ "safer-buffer": "~2.1.0" } }, - "asn1.js": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", - "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", - "dev": true, - "requires": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "safer-buffer": "^2.1.0" - } - }, "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", @@ -18994,9 +17526,9 @@ "dev": true }, "astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true }, "async": { @@ -19042,9 +17574,9 @@ "dev": true }, "aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", + "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", "dev": true }, "balanced-match": { @@ -19158,13 +17690,13 @@ "dev": true }, "body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "dev": true, "requires": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", @@ -19172,7 +17704,7 @@ "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.11.0", - "raw-body": "2.5.1", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -19266,72 +17798,6 @@ "safe-buffer": "^5.0.1" } }, - "browserify-cipher": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", - "dev": true, - "requires": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "browserify-des": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", - "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", - "dev": true, - "requires": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "browserify-rsa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", - "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", - "dev": true, - "requires": { - "bn.js": "^5.0.0", - "randombytes": "^2.0.1" - }, - "dependencies": { - "bn.js": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", - "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", - "dev": true - } - } - }, - "browserify-sign": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", - "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", - "dev": true, - "requires": { - "bn.js": "^5.1.1", - "browserify-rsa": "^4.0.1", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "elliptic": "^6.5.3", - "inherits": "^2.0.4", - "parse-asn1": "^5.1.5", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - }, - "dependencies": { - "bn.js": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", - "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", - "dev": true - } - } - }, "bs58": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", @@ -19458,32 +17924,6 @@ "get-intrinsic": "^1.0.2" } }, - "caller-callsite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", - "integrity": "sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ==", - "dev": true, - "requires": { - "callsites": "^2.0.0" - }, - "dependencies": { - "callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ==", - "dev": true - } - } - }, - "caller-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A==", - "dev": true, - "requires": { - "caller-callsite": "^2.0.0" - } - }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -19522,12 +17962,6 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true - }, - "quick-lru": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", - "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", - "dev": true } } }, @@ -19544,21 +17978,12 @@ "dev": true }, "cbor": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/cbor/-/cbor-5.2.0.tgz", - "integrity": "sha512-5IMhi9e1QU76ppa5/ajP1BmMWZ2FHkhAhjeVKQ/EFCgYSEaeVaoGtL7cxJskf9oCCk+XjzaIdc3IuU/dbA/o2A==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/cbor/-/cbor-8.1.0.tgz", + "integrity": "sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==", "dev": true, "requires": { - "bignumber.js": "^9.0.1", - "nofilter": "^1.0.4" - }, - "dependencies": { - "bignumber.js": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz", - "integrity": "sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig==", - "dev": true - } + "nofilter": "^3.1.0" } }, "chai": { @@ -19584,13 +18009,14 @@ "requires": {} }, "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, "change-case": { @@ -19689,9 +18115,9 @@ "dev": true }, "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", "dev": true }, "cids": { @@ -19754,15 +18180,6 @@ "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", "dev": true }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, "cli-table3": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz", @@ -19774,12 +18191,6 @@ "string-width": "^2.1.1" } }, - "cli-width": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", - "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", - "dev": true - }, "cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -19847,18 +18258,18 @@ "dev": true }, "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, "requires": { - "color-name": "~1.1.4" + "color-name": "1.1.3" } }, "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, "colors": { @@ -19883,9 +18294,9 @@ "dev": true }, "commander": { - "version": "2.18.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.18.0.tgz", - "integrity": "sha512-6CYPa+JP2ftfRU2qkDK+UTVeQYosOg/2GbcjIcKPHfinyOLPVGXu/ovN86RP49Re5ndJK1N0kuiidFFuepc4ZQ==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.0.tgz", + "integrity": "sha512-zS5PnTI22FIRM6ylNW8G4Ap0IEOyk62fhLSD0+uHRT9McRCLGpkVNvao4bjimpK/GShynyQkFFxHhwMcETmduA==", "dev": true }, "compare-versions": { @@ -19913,9 +18324,9 @@ }, "dependencies": { "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -19975,9 +18386,9 @@ } }, "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "dev": true }, "cookie": { @@ -20009,32 +18420,31 @@ } }, "cosmiconfig": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", - "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.0.0.tgz", + "integrity": "sha512-da1EafcpH6b/TD8vDRaWV7xFINlHlF6zKsGwS1TsuVJTZRkquaS5HTMq7uq6h31619QjbsYl21gVDOm32KM1vQ==", "dev": true, "requires": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.0.0" + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0" }, "dependencies": { - "import-fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==", + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "requires": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" + "argparse": "^2.0.1" } - }, - "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", - "dev": true } } }, @@ -20044,16 +18454,6 @@ "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", "dev": true }, - "create-ecdh": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", - "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "elliptic": "^6.5.3" - } - }, "create-hash": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", @@ -20088,6 +18488,17 @@ "dev": true, "requires": { "node-fetch": "2.6.7" + }, + "dependencies": { + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dev": true, + "requires": { + "whatwg-url": "^5.0.0" + } + } } }, "cross-spawn": { @@ -20122,25 +18533,6 @@ "sha3": "^2.1.1" } }, - "crypto-browserify": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", - "dev": true, - "requires": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" - } - }, "crypto-js": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.3.0.tgz", @@ -20237,9 +18629,9 @@ } }, "decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", "dev": true }, "decamelize-keys": { @@ -20252,12 +18644,6 @@ "map-obj": "^1.0.0" }, "dependencies": { - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true - }, "map-obj": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", @@ -20320,9 +18706,9 @@ "dev": true }, "define-properties": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", - "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", "dev": true, "requires": { "has-property-descriptors": "^1.0.0", @@ -20341,16 +18727,6 @@ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "dev": true }, - "des.js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", - "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, "destroy": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", @@ -20358,9 +18734,9 @@ "dev": true }, "detect-indent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz", - "integrity": "sha512-rlpvsxUtM0PQvy9iZe640/IWwWYyBsTApREbA1pHOpmOUIl9MkP/U4z7vTtg4Oaojvqhxt7sdufnT0EzGaR31g==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", "dev": true }, "detect-port": { @@ -20379,17 +18755,6 @@ "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", "dev": true }, - "diffie-hellman": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - } - }, "difflib": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/difflib/-/difflib-0.2.4.tgz", @@ -20534,14 +18899,6 @@ "dev": true, "requires": { "ansi-colors": "^4.1.1" - }, - "dependencies": { - "ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true - } } }, "entities": { @@ -20566,27 +18923,33 @@ } }, "es-abstract": { - "version": "1.20.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.5.tgz", - "integrity": "sha512-7h8MM2EQhsCA7pU/Nv78qOXFpD8Rhqd12gYiSJVkrH9+e8VuA8JlPJK/hQjjlLv6pJvx/z1iRFKzYb0XT/RuAQ==", + "version": "1.21.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.1.tgz", + "integrity": "sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==", "dev": true, "requires": { + "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "function.prototype.name": "^1.1.5", "get-intrinsic": "^1.1.3", "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", "gopd": "^1.0.1", "has": "^1.0.3", "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", + "internal-slot": "^1.0.4", + "is-array-buffer": "^3.0.1", "is-callable": "^1.2.7", "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", "is-weakref": "^1.0.2", "object-inspect": "^1.12.2", "object-keys": "^1.1.1", @@ -20595,21 +18958,9 @@ "safe-regex-test": "^1.0.0", "string.prototype.trimend": "^1.0.6", "string.prototype.trimstart": "^1.0.6", - "unbox-primitive": "^1.0.2" - }, - "dependencies": { - "object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - } - } + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.9" } }, "es-array-method-boxes-properly": { @@ -20618,6 +18969,17 @@ "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", "dev": true }, + "es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + } + }, "es-shim-unscopables": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", @@ -20689,9 +19051,9 @@ "dev": true }, "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true }, "escodegen": { @@ -20761,9 +19123,9 @@ } }, "eslint": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.31.0.tgz", - "integrity": "sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==", + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.34.0.tgz", + "integrity": "sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==", "dev": true, "requires": { "@eslint/eslintrc": "^1.4.1", @@ -20813,6 +19175,15 @@ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, "argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -20829,6 +19200,27 @@ "supports-color": "^7.1.0" } }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, "find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -20848,6 +19240,12 @@ "is-glob": "^4.0.3" } }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, "js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -20892,6 +19290,15 @@ "requires": { "ansi-regex": "^5.0.1" } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } } } }, @@ -20953,9 +19360,9 @@ "dev": true }, "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.2.tgz", + "integrity": "sha512-JVSoLdTlTDkmjFmab7H/9SL9qGSyjElT3myyKp7krqjVFQCDLmj1QFaCLRFBszBKI0XVZaiiXvuPIX3ZwHe1Ng==", "dev": true, "requires": { "estraverse": "^5.1.0" @@ -21041,43 +19448,12 @@ "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", "dev": true }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, "camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, "chokidar": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", @@ -21105,21 +19481,6 @@ "wrap-ansi": "^5.1.0" } }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, "debug": { "version": "3.2.6", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", @@ -21129,12 +19490,6 @@ "ms": "^2.1.1" } }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true - }, "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", @@ -21147,22 +19502,16 @@ "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "dev": true }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, "ethereum-cryptography": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.1.2.tgz", - "integrity": "sha512-XDSJlg4BD+hq9N2FjvotwUET9Tfxpxc3kWGE2AqUG5vcbeunnbImVk3cj6e/xT3phdW21mE8R5IugU4fspQDcQ==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz", + "integrity": "sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==", "dev": true, "requires": { - "@noble/hashes": "1.1.2", - "@noble/secp256k1": "1.6.3", - "@scure/bip32": "1.1.0", - "@scure/bip39": "1.1.0" + "@noble/hashes": "1.2.0", + "@noble/secp256k1": "1.7.1", + "@scure/bip32": "1.1.5", + "@scure/bip39": "1.1.1" } }, "find-up": { @@ -21204,12 +19553,6 @@ "path-is-absolute": "^1.0.0" } }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, "js-yaml": { "version": "3.13.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", @@ -21295,6 +19638,18 @@ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", "dev": true }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, "p-locate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", @@ -21783,6 +20138,26 @@ "vary": "~1.1.2" }, "dependencies": { + "body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dev": true, + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + } + }, "cookie": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", @@ -21803,6 +20178,18 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true + }, + "raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dev": true, + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } } } }, @@ -21907,23 +20294,6 @@ "reusify": "^1.0.4" } }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - }, - "dependencies": { - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - } - } - }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -22154,9 +20524,9 @@ "dev": true }, "get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", "dev": true, "requires": { "function-bind": "^1.1.1", @@ -22203,70 +20573,12 @@ "requires": { "chalk": "^2.4.2", "node-emoji": "^1.10.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } } }, "glob": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", - "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -22286,9 +20598,9 @@ } }, "minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, "requires": { "brace-expansion": "^2.0.1" @@ -22347,44 +20659,35 @@ } }, "globals": { - "version": "13.19.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", - "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", "dev": true, "requires": { "type-fest": "^0.20.2" } }, - "globby": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz", - "integrity": "sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==", + "globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3" + } + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, "requires": { - "@types/glob": "^7.1.1", "array-union": "^2.1.0", "dir-glob": "^3.0.1", - "fast-glob": "^3.0.3", - "glob": "^7.1.3", - "ignore": "^5.1.1", - "merge2": "^1.2.3", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", "slash": "^3.0.0" - }, - "dependencies": { - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } } }, "gopd": { @@ -22488,9 +20791,9 @@ "dev": true }, "hardhat": { - "version": "2.12.5", - "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.12.5.tgz", - "integrity": "sha512-f/t7+hLlhsnQZ6LDXyV+8rHGRZFZY1sgFvgrwr9fBjMdGp1Bu6hHq1KXS4/VFZfZcVdL1DAWWEkryinZhqce+A==", + "version": "2.12.7", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.12.7.tgz", + "integrity": "sha512-voWoN6zn5d8BOEaczSyK/1PyfdeOeI3SbGCFb36yCHTJUt6OIqLb+ZDX30VhA1UsYKzLqG7UnWl3fKJUuANc6A==", "dev": true, "requires": { "@ethersproject/abi": "^5.1.2", @@ -22540,44 +20843,15 @@ "source-map-support": "^0.5.13", "stacktrace-parser": "^0.1.10", "tsort": "0.0.1", - "undici": "^5.4.0", + "undici": "^5.14.0", "uuid": "^8.3.2", "ws": "^7.4.6" }, "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", "dev": true }, "commander": { @@ -22586,22 +20860,16 @@ "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==", "dev": true }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, "ethereum-cryptography": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.1.2.tgz", - "integrity": "sha512-XDSJlg4BD+hq9N2FjvotwUET9Tfxpxc3kWGE2AqUG5vcbeunnbImVk3cj6e/xT3phdW21mE8R5IugU4fspQDcQ==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz", + "integrity": "sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==", "dev": true, "requires": { - "@noble/hashes": "1.1.2", - "@noble/secp256k1": "1.6.3", - "@scure/bip32": "1.1.0", - "@scure/bip39": "1.1.0" + "@noble/hashes": "1.2.0", + "@noble/secp256k1": "1.7.1", + "@scure/bip32": "1.1.5", + "@scure/bip39": "1.1.1" } }, "find-up": { @@ -22627,12 +20895,6 @@ "path-is-absolute": "^1.0.0" } }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, "jsonfile": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", @@ -22740,22 +21002,13 @@ "dev": true } } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } } } }, "hardhat-exposed": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/hardhat-exposed/-/hardhat-exposed-0.3.1.tgz", - "integrity": "sha512-qyHXdS3NmzrtXF+XL547BMsTAK+IEMW9OOYMH4d362DlPn4L2B2KXKG6OpuJczxYjgMFJ0LunLxNgu6jtRvjRg==", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/hardhat-exposed/-/hardhat-exposed-0.3.2.tgz", + "integrity": "sha512-qhi60I2bfjoPZwKgrY7BIpuUiBE7aC/bHN2MzHxPcZdxaeFnjKJ50n59LE7yK3GK2qYzE8DMjzqfnH6SlKPUjw==", "dev": true, "requires": { "micromatch": "^4.0.4", @@ -22774,9 +21027,9 @@ } }, "hardhat-ignore-warnings": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/hardhat-ignore-warnings/-/hardhat-ignore-warnings-0.2.6.tgz", - "integrity": "sha512-GQgvjprONI8VF8b85+QJ8H9v3L9TCCtQvUx+9QaRL+sCPw1cOZHfhlEz9V6Lq7GNCQMqBORVzNzUzoP/tKAEQQ==", + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/hardhat-ignore-warnings/-/hardhat-ignore-warnings-0.2.8.tgz", + "integrity": "sha512-vPX94rJyTzYsCOzGIYdOcJgn3iQI6qa+CI9ZZfgDhdXJpda8ljpOT7bdUKAYC4LyoP0Z5fWTmupXoPaQrty0gw==", "dev": true, "requires": { "minimatch": "^5.1.0", @@ -22794,9 +21047,9 @@ } }, "minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, "requires": { "brace-expansion": "^2.0.1" @@ -22820,9 +21073,9 @@ "dev": true }, "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true }, "has-property-descriptors": { @@ -22834,6 +21087,12 @@ "get-intrinsic": "^1.1.1" } }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true + }, "has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", @@ -22899,9 +21158,9 @@ "dev": true }, "highlightjs-solidity": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/highlightjs-solidity/-/highlightjs-solidity-2.0.5.tgz", - "integrity": "sha512-ReXxQSGQkODMUgHcWzVSnfDCDrL2HshOYgw3OlIYmfHeRzUPkfJTUIp95pK4CmbiNG2eMTOmNLpfCz9Zq7Cwmg==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/highlightjs-solidity/-/highlightjs-solidity-2.0.6.tgz", + "integrity": "sha512-DySXWfQghjm2l6a/flF+cteroJqD4gI8GSdL4PtvxZSsAHie8m3yVe2JFoRg03ROKT6hp2Lc/BxXkqerNmtQYg==", "dev": true }, "hmac-drbg": { @@ -23006,6 +21265,14 @@ "requires": { "quick-lru": "^5.1.1", "resolve-alpn": "^1.2.0" + }, + "dependencies": { + "quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true + } } }, "https-proxy-agent": { @@ -23055,9 +21322,9 @@ "dev": true }, "immutable": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.2.1.tgz", - "integrity": "sha512-7WYV7Q5BTs0nlQm7tl92rDYYoyELLKHoDMBKhrxEoiV4mrfVdRz8hzPiYOzH7yWjzoVEamxRuAqhxL2PLRwZYQ==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.2.4.tgz", + "integrity": "sha512-WDxL3Hheb1JkRN3sQkyujNlL/xRjAo3rJtaU5xeufUauG66JdMr32bLj4gF+vWl84DIA3Zxw7tiAjneYzRRw+w==", "dev": true }, "import-fresh": { @@ -23068,6 +21335,14 @@ "requires": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } } }, "imurmurhash": { @@ -23104,113 +21379,13 @@ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true }, - "inquirer": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", - "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", - "dev": true, - "requires": { - "ansi-escapes": "^3.2.0", - "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.3", - "figures": "^2.0.0", - "lodash": "^4.17.12", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^6.4.0", - "string-width": "^2.1.0", - "strip-ansi": "^5.1.0", - "through": "^2.3.6" - }, - "dependencies": { - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true - }, - "ansi-regex": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", - "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, "internal-slot": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.4.tgz", - "integrity": "sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", "dev": true, "requires": { - "get-intrinsic": "^1.1.3", + "get-intrinsic": "^1.2.0", "has": "^1.0.3", "side-channel": "^1.0.4" } @@ -23252,6 +21427,17 @@ "has-tostringtag": "^1.0.0" } }, + "is-array-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.1.tgz", + "integrity": "sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-typed-array": "^1.1.10" + } + }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -23305,14 +21491,6 @@ "dev": true, "requires": { "ci-info": "^3.2.0" - }, - "dependencies": { - "ci-info": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.1.tgz", - "integrity": "sha512-4jYS4MOAaCIStSRwiuxc4B8MYhIe676yO1sYGzARnjXkWpmzZMMYxY6zu8WYWDhSuth5zhrQ1rhNSibyyvv4/w==", - "dev": true - } } }, "is-date-object": { @@ -23324,12 +21502,6 @@ "has-tostringtag": "^1.0.0" } }, - "is-directory": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw==", - "dev": true - }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -23409,9 +21581,9 @@ "dev": true }, "is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", "dev": true }, "is-port-reachable": { @@ -23540,9 +21712,9 @@ "dev": true }, "js-sdsl": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", - "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", + "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", "dev": true }, "js-sha3": { @@ -23579,12 +21751,6 @@ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, "json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", @@ -23802,6 +21968,15 @@ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", "dev": true + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } } } }, @@ -23815,14 +21990,6 @@ "js-yaml": "^3.13.0", "pify": "^4.0.1", "strip-bom": "^3.0.0" - }, - "dependencies": { - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true - } } }, "locate-path": { @@ -23864,6 +22031,12 @@ "integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==", "dev": true }, + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true + }, "lodash.zip": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.zip/-/lodash.zip-4.2.0.tgz", @@ -23880,6 +22053,15 @@ "is-unicode-supported": "^0.1.0" }, "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -23889,6 +22071,36 @@ "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } } } }, @@ -24008,84 +22220,11 @@ "yargs-parser": "^18.1.3" }, "dependencies": { - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "requires": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "dependencies": { - "type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true - } - } - }, - "read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "requires": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, - "dependencies": { - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true - } - } - }, "type-fest": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", "dev": true - }, - "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } } } }, @@ -24138,16 +22277,6 @@ "picomatch": "^2.3.1" } }, - "miller-rabin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "dev": true, - "requires": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - } - }, "mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -24169,12 +22298,6 @@ "mime-db": "1.52.0" } }, - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true - }, "mimic-response": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", @@ -24218,9 +22341,9 @@ } }, "minimist": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", - "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true }, "minimist-options": { @@ -24232,14 +22355,6 @@ "arrify": "^1.0.1", "is-plain-obj": "^1.1.0", "kind-of": "^6.0.3" - }, - "dependencies": { - "is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", - "dev": true - } } }, "minipass": { @@ -24262,9 +22377,9 @@ } }, "mixme": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/mixme/-/mixme-0.5.4.tgz", - "integrity": "sha512-3KYa4m4Vlqx98GPdOHghxSdNtTvcP8E0kkaJ5Dlh+h2DRzF7zpuVVcA8B0QpKd11YJeP9QQ7ASkKzOeu195Wzw==", + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mixme/-/mixme-0.5.5.tgz", + "integrity": "sha512-/6IupbRx32s7jjEwHcycXikJwFD5UujbVNuJFkeKLYje+92OvtuPniF6JhnFm5JCTDUhS+kYK3W/4BWYQYXz7w==", "dev": true }, "mkdirp": { @@ -24352,6 +22467,12 @@ "wrap-ansi": "^7.0.0" } }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, "find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -24387,6 +22508,12 @@ } } }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -24498,6 +22625,12 @@ "y18n": "^5.0.5", "yargs-parser": "^20.2.2" } + }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true } } }, @@ -24561,12 +22694,6 @@ } } }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ==", - "dev": true - }, "nano-base32": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/nano-base32/-/nano-base32-1.0.1.tgz", @@ -24615,12 +22742,6 @@ "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", "dev": true }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, "no-case": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", @@ -24664,18 +22785,18 @@ } }, "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", + "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", "dev": true, "requires": { "whatwg-url": "^5.0.0" } }, "node-gyp-build": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.5.0.tgz", - "integrity": "sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz", + "integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==", "dev": true }, "node-interval-tree": { @@ -24688,9 +22809,9 @@ } }, "nofilter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-1.0.4.tgz", - "integrity": "sha512-N8lidFp+fCz+TD51+haYdbDGrcBWwuHX40F5+z0qkUjMJ5Tp+rdSuAkMJ9N9eoolDlEVTf6u5icM+cNKkKW2mA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz", + "integrity": "sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==", "dev": true }, "nopt": { @@ -24780,9 +22901,9 @@ "dev": true }, "object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", "dev": true }, "object-keys": { @@ -24792,15 +22913,15 @@ "dev": true }, "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", "dev": true, "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" } }, "object.getownpropertydescriptors": { @@ -24848,15 +22969,6 @@ "wrappy": "1" } }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, "optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -24972,19 +23084,6 @@ "callsites": "^3.0.0" } }, - "parse-asn1": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", - "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", - "dev": true, - "requires": { - "asn1.js": "^5.2.0", - "browserify-aes": "^1.0.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3", - "safe-buffer": "^5.1.1" - } - }, "parse-cache-control": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", @@ -24998,13 +23097,15 @@ "dev": true }, "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "requires": { + "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" } }, "parse5": { @@ -25063,12 +23164,6 @@ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", - "dev": true - }, "path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -25154,6 +23249,12 @@ "find-up": "^4.0.0" } }, + "pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true + }, "preferred-pm": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/preferred-pm/-/preferred-pm-3.0.3.tgz", @@ -25212,45 +23313,30 @@ "dev": true }, "prettier": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.1.tgz", - "integrity": "sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg==", + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", + "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", "dev": true }, "prettier-plugin-solidity": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.1.1.tgz", - "integrity": "sha512-uD24KO26tAHF+zMN2nt1OUzfknzza5AgxjogQQrMLZc7j8xiQrDoNWNeOlfFC0YLTwo12CLD10b9niLyP6AqXg==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.1.2.tgz", + "integrity": "sha512-KC5oNbFJfyBaFiO0kl56J6AXnDmr9tUlBV1iqo864x4KQrKYKaBZvW9jhT2oC0NHoNp7/GoMJNxqL8pp8k7C/g==", "dev": true, "requires": { - "@solidity-parser/parser": "^0.14.5", + "@solidity-parser/parser": "^0.15.0", "semver": "^7.3.8", "solidity-comments-extractor": "^0.0.7" }, "dependencies": { - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "@solidity-parser/parser": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.15.0.tgz", + "integrity": "sha512-5UFJJTzWi1hgFk6aGCZ5rxG2DJkCJOzJ74qg7UkWSNCDSigW+CJLoYUb5bLiKrtI34Nr9rpFSUNHfkqtlL+N/w==", "dev": true, "requires": { - "yallist": "^4.0.0" + "antlr4ts": "^0.5.0-alpha.4" } - }, - "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true } } }, @@ -25266,12 +23352,6 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, "promise": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", @@ -25314,20 +23394,6 @@ "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", "dev": true }, - "public-encrypt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", - "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -25377,9 +23443,9 @@ "dev": true }, "quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", "dev": true }, "randombytes": { @@ -25391,16 +23457,6 @@ "safe-buffer": "^5.1.0" } }, - "randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "dev": true, - "requires": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, "range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -25408,9 +23464,9 @@ "dev": true }, "raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dev": true, "requires": { "bytes": "3.1.2", @@ -25420,63 +23476,41 @@ } }, "read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", "dev": true, "requires": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" }, "dependencies": { - "path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", "dev": true } } }, "read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", "dev": true, "requires": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" }, "dependencies": { - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", - "dev": true, - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" - } + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true } } }, @@ -25490,20 +23524,12 @@ "js-yaml": "^3.6.1", "pify": "^4.0.1", "strip-bom": "^3.0.0" - }, - "dependencies": { - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true - } } }, "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.1.tgz", + "integrity": "sha512-+rQmrWMYGA90yenhTYsLWAsLsqVC8osOw6PKE1HDYiO0gdPeKe/xDHNzIAIn4C91YQ6oenEhfYqqc1883qHbjQ==", "dev": true, "requires": { "inherits": "^2.0.3", @@ -25704,9 +23730,9 @@ "dev": true }, "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true }, "responselike": { @@ -25726,16 +23752,6 @@ } } }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", - "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - }, "retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", @@ -25806,12 +23822,6 @@ } } }, - "run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true - }, "run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -25836,15 +23846,6 @@ "integrity": "sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA==", "dev": true }, - "rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -26239,38 +24240,44 @@ "dev": true }, "slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, "requires": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" }, "dependencies": { "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "color-convert": "^1.9.0" + "color-convert": "^2.0.1" } }, "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "requires": { - "color-name": "1.1.3" + "color-name": "~1.1.4" } }, "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true } } @@ -26295,11 +24302,14 @@ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } }, "cliui": { "version": "6.0.0", @@ -26312,10 +24322,19 @@ "wrap-ansi": "^6.2.0" } }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, "is-fullwidth-code-point": { @@ -26379,16 +24398,6 @@ "y18n": "^4.0.0", "yargs-parser": "^18.1.2" } - }, - "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } } } }, @@ -26437,11 +24446,15 @@ "wrap-ansi": "^2.0.0" } }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } }, "fs-extra": { "version": "0.30.0", @@ -26494,6 +24507,53 @@ "graceful-fs": "^4.1.6" } }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", + "dev": true, + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + } + }, "require-main-filename": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", @@ -26592,304 +24652,99 @@ } }, "solhint": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/solhint/-/solhint-3.3.7.tgz", - "integrity": "sha512-NjjjVmXI3ehKkb3aNtRJWw55SUVJ8HMKKodwe0HnejA+k0d2kmhw7jvpa+MCTbcEgt8IWSwx0Hu6aCo/iYOZzQ==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/solhint/-/solhint-3.4.0.tgz", + "integrity": "sha512-FYEs/LoTxMsWFP/OGsEqR1CBDn3Bn7hrTWsgtjai17MzxITgearIdlo374KKZjjIycu8E2xBcJ+RSWeoBvQmkw==", "dev": true, "requires": { - "@solidity-parser/parser": "^0.14.1", - "ajv": "^6.6.1", - "antlr4": "4.7.1", - "ast-parents": "0.0.1", - "chalk": "^2.4.2", - "commander": "2.18.0", - "cosmiconfig": "^5.0.7", - "eslint": "^5.6.0", - "fast-diff": "^1.1.2", - "glob": "^7.1.3", - "ignore": "^4.0.6", - "js-yaml": "^3.12.0", - "lodash": "^4.17.11", - "prettier": "^1.14.3", - "semver": "^6.3.0" + "@solidity-parser/parser": "^0.15.0", + "ajv": "^6.12.6", + "antlr4": "^4.11.0", + "ast-parents": "^0.0.1", + "chalk": "^4.1.2", + "commander": "^10.0.0", + "cosmiconfig": "^8.0.0", + "fast-diff": "^1.2.0", + "glob": "^8.0.3", + "ignore": "^5.2.4", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "pluralize": "^8.0.0", + "prettier": "^2.8.3", + "semver": "^6.3.0", + "strip-ansi": "^6.0.1", + "table": "^6.8.1", + "text-table": "^0.2.0" }, "dependencies": { - "acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "@solidity-parser/parser": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.15.0.tgz", + "integrity": "sha512-5UFJJTzWi1hgFk6aGCZ5rxG2DJkCJOzJ74qg7UkWSNCDSigW+CJLoYUb5bLiKrtI34Nr9rpFSUNHfkqtlL+N/w==", + "dev": true, + "requires": { + "antlr4ts": "^0.5.0-alpha.4" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "color-convert": "^1.9.0" + "color-convert": "^2.0.1" } }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "requires": { - "color-name": "1.1.3" + "color-name": "~1.1.4" } }, "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "eslint": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz", - "integrity": "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.9.1", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "eslint-scope": "^4.0.3", - "eslint-utils": "^1.3.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^5.0.1", - "esquery": "^1.0.1", - "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", - "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", - "globals": "^11.7.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "inquirer": "^6.2.2", - "js-yaml": "^3.13.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.11", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", - "progress": "^2.0.0", - "regexpp": "^2.0.1", - "semver": "^5.5.1", - "strip-ansi": "^4.0.0", - "strip-json-comments": "^2.0.1", - "table": "^5.2.3", - "text-table": "^0.2.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "eslint-scope": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", - "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", - "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - } - }, - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - }, - "espree": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", - "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", - "dev": true, - "requires": { - "acorn": "^6.0.7", - "acorn-jsx": "^5.0.0", - "eslint-visitor-keys": "^1.0.0" - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", - "dev": true, - "requires": { - "flat-cache": "^2.0.1" - } - }, - "flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", - "dev": true, - "requires": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" - } - }, - "flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", - "dev": true - }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", - "dev": true - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "dev": true - }, - "prettier": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", - "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", - "dev": true, - "optional": true - }, - "regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", - "dev": true - }, - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "requires": { - "glob": "^7.1.3" + "argparse": "^2.0.1" } }, "semver": { @@ -26898,60 +24753,30 @@ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "shebang-regex": "^1.0.0" + "ansi-regex": "^5.0.1" } }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", - "dev": true - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "dev": true - }, "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "requires": { - "has-flag": "^3.0.0" - } - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" + "has-flag": "^4.0.0" } } } }, "solidity-ast": { - "version": "0.4.40", - "resolved": "https://registry.npmjs.org/solidity-ast/-/solidity-ast-0.4.40.tgz", - "integrity": "sha512-M8uLBT2jgFB7B0iVAC5a2l71J8vim7aEm03AZkaHbDqyrl1pE+i5PriMEw6WlwGfHp3/Ym7cn9BqvVLQgRk+Yw==", + "version": "0.4.46", + "resolved": "https://registry.npmjs.org/solidity-ast/-/solidity-ast-0.4.46.tgz", + "integrity": "sha512-MlPZQfPhjWXqh7YxWcBGDXaPZIfMYCOHYoLEhGDWulNwEPIQQZuB7mA9eP17CU0jY/bGR4avCEUVVpvHtT2gbA==", "dev": true }, "solidity-comments": { @@ -27088,32 +24913,12 @@ "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", "dev": true }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, "camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, "chokidar": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", @@ -27141,21 +24946,6 @@ "wrap-ansi": "^5.1.0" } }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, "debug": { "version": "3.2.6", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", @@ -27165,12 +24955,6 @@ "ms": "^2.1.1" } }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true - }, "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", @@ -27183,12 +24967,6 @@ "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "dev": true }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, "find-up": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", @@ -27226,24 +25004,34 @@ "optional": true }, "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true + "globby": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz", + "integrity": "sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.0.3", + "glob": "^7.1.3", + "ignore": "^5.1.1", + "merge2": "^1.2.3", + "slash": "^3.0.0" + } }, "js-yaml": { "version": "3.13.1", @@ -27274,15 +25062,6 @@ "chalk": "^2.4.2" } }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, "mkdirp": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", @@ -27324,13 +25103,27 @@ "yargs-unparser": "1.6.0" }, "dependencies": { - "supports-color": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", - "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" } } } @@ -27341,6 +25134,18 @@ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", "dev": true }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, "p-locate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", @@ -27392,9 +25197,9 @@ "dev": true }, "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "dev": true, "requires": { "has-flag": "^3.0.0" @@ -27732,13 +25537,10 @@ } }, "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", - "dev": true, - "requires": { - "is-utf8": "^0.2.0" - } + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true }, "strip-hex-prefix": { "version": "1.0.0", @@ -27762,12 +25564,12 @@ "dev": true }, "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { - "has-flag": "^4.0.0" + "has-flag": "^3.0.0" } }, "swap-case": { @@ -27865,6 +25667,12 @@ "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", "dev": true + }, + "quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true } } }, @@ -27889,47 +25697,72 @@ } }, "table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", + "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", "dev": true, "requires": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" }, "dependencies": { + "ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, "ansi-regex": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", - "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true }, "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" } }, "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^4.1.0" + "ansi-regex": "^5.0.1" } } } @@ -27994,12 +25827,6 @@ } } }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true - }, "timed-out": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", @@ -28051,9 +25878,9 @@ }, "dependencies": { "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", "dev": true } } @@ -28109,6 +25936,15 @@ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -28119,6 +25955,27 @@ "supports-color": "^7.1.0" } }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -28127,6 +25984,15 @@ "requires": { "ansi-regex": "^5.0.1" } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } } } }, @@ -28188,6 +26054,17 @@ "mime-types": "~2.1.24" } }, + "typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + } + }, "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", @@ -28235,9 +26112,9 @@ "dev": true }, "undici": { - "version": "5.14.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.14.0.tgz", - "integrity": "sha512-yJlHYw6yXPPsuOH0x2Ib1Km61vu4hLiRRQoafs+WUgX1vO64vgnxiCEN9dpIrhZyHFsai3F0AEj4P9zy19enEQ==", + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.20.0.tgz", + "integrity": "sha512-J3j60dYzuo6Eevbawwp1sdg16k5Tf768bxYK4TUJRH7cBM4kFCbf3mOnM/0E3vQYXvpxITbbWmBafaDbxLDz3g==", "dev": true, "requires": { "busboy": "^1.6.0" @@ -28374,60 +26251,46 @@ } }, "web3": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3/-/web3-1.8.1.tgz", - "integrity": "sha512-tAqFsQhGv340C9OgRJIuoScN7f7wa1tUvsnnDUMt9YE6J4gcm7TV2Uwv+KERnzvV+xgdeuULYpsioRRNKrUvoQ==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.8.2.tgz", + "integrity": "sha512-92h0GdEHW9wqDICQQKyG4foZBYi0OQkyg4CRml2F7XBl/NG+fu9o6J19kzfFXzSBoA4DnJXbyRgj/RHZv5LRiw==", "dev": true, "requires": { - "web3-bzz": "1.8.1", - "web3-core": "1.8.1", - "web3-eth": "1.8.1", - "web3-eth-personal": "1.8.1", - "web3-net": "1.8.1", - "web3-shh": "1.8.1", - "web3-utils": "1.8.1" + "web3-bzz": "1.8.2", + "web3-core": "1.8.2", + "web3-eth": "1.8.2", + "web3-eth-personal": "1.8.2", + "web3-net": "1.8.2", + "web3-shh": "1.8.2", + "web3-utils": "1.8.2" } }, "web3-bzz": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.8.1.tgz", - "integrity": "sha512-dJJHS84nvpoxv6ijTMkdUSlRr5beCXNtx4UZcrFLHBva8dT63QEtKdLyDt2AyMJJdVzTCk78uir/6XtVWrdS6w==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.8.2.tgz", + "integrity": "sha512-1EEnxjPnFnvNWw3XeeKuTR8PBxYd0+XWzvaLK7OJC/Go9O8llLGxrxICbKV+8cgIE0sDRBxiYx02X+6OhoAQ9w==", "dev": true, "requires": { "@types/node": "^12.12.6", "got": "12.1.0", "swarm-js": "^0.1.40" - }, - "dependencies": { - "@types/node": { - "version": "12.20.55", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", - "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", - "dev": true - } } }, "web3-core": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.8.1.tgz", - "integrity": "sha512-LbRZlJH2N6nS3n3Eo9Y++25IvzMY7WvYnp4NM/Ajhh97dAdglYs6rToQ2DbL2RLvTYmTew4O/y9WmOk4nq9COw==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.8.2.tgz", + "integrity": "sha512-DJTVEAYcNqxkqruJE+Rxp3CIv0y5AZMwPHQmOkz/cz+MM75SIzMTc0AUdXzGyTS8xMF8h3YWMQGgGEy8SBf1PQ==", "dev": true, "requires": { "@types/bn.js": "^5.1.0", "@types/node": "^12.12.6", "bignumber.js": "^9.0.0", - "web3-core-helpers": "1.8.1", - "web3-core-method": "1.8.1", - "web3-core-requestmanager": "1.8.1", - "web3-utils": "1.8.1" + "web3-core-helpers": "1.8.2", + "web3-core-method": "1.8.2", + "web3-core-requestmanager": "1.8.2", + "web3-utils": "1.8.2" }, "dependencies": { - "@types/node": { - "version": "12.20.55", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", - "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", - "dev": true - }, "bignumber.js": { "version": "9.1.1", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz", @@ -28437,107 +26300,106 @@ } }, "web3-core-helpers": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.8.1.tgz", - "integrity": "sha512-ClzNO6T1S1gifC+BThw0+GTfcsjLEY8T1qUp6Ly2+w4PntAdNtKahxWKApWJ0l9idqot/fFIDXwO3Euu7I0Xqw==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.8.2.tgz", + "integrity": "sha512-6B1eLlq9JFrfealZBomd1fmlq1o4A09vrCVQSa51ANoib/jllT3atZrRDr0zt1rfI7TSZTZBXdN/aTdeN99DWw==", "dev": true, "requires": { - "web3-eth-iban": "1.8.1", - "web3-utils": "1.8.1" + "web3-eth-iban": "1.8.2", + "web3-utils": "1.8.2" } }, "web3-core-method": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.8.1.tgz", - "integrity": "sha512-oYGRodktfs86NrnFwaWTbv2S38JnpPslFwSSARwFv4W9cjbGUW3LDeA5MKD/dRY+ssZ5OaekeMsUCLoGhX68yA==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.8.2.tgz", + "integrity": "sha512-1qnr5mw5wVyULzLOrk4B+ryO3gfGjGd/fx8NR+J2xCGLf1e6OSjxT9vbfuQ3fErk/NjSTWWreieYWLMhaogcRA==", "dev": true, "requires": { "@ethersproject/transactions": "^5.6.2", - "web3-core-helpers": "1.8.1", - "web3-core-promievent": "1.8.1", - "web3-core-subscriptions": "1.8.1", - "web3-utils": "1.8.1" + "web3-core-helpers": "1.8.2", + "web3-core-promievent": "1.8.2", + "web3-core-subscriptions": "1.8.2", + "web3-utils": "1.8.2" } }, "web3-core-promievent": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.8.1.tgz", - "integrity": "sha512-9mxqHlgB0MrZI4oUIRFkuoJMNj3E7btjrMv3sMer/Z9rYR1PfoSc1aAokw4rxKIcAh+ylVtd/acaB2HKB7aRPg==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.8.2.tgz", + "integrity": "sha512-nvkJWDVgoOSsolJldN33tKW6bKKRJX3MCPDYMwP5SUFOA/mCzDEoI88N0JFofDTXkh1k7gOqp1pvwi9heuaxGg==", "dev": true, "requires": { "eventemitter3": "4.0.4" } }, "web3-core-requestmanager": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.8.1.tgz", - "integrity": "sha512-x+VC2YPPwZ1khvqA6TA69LvfFCOZXsoUVOxmTx/vIN22PrY9KzKhxcE7pBSiGhmab1jtmRYXUbcQSVpAXqL8cw==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.8.2.tgz", + "integrity": "sha512-p1d090RYs5Mu7DK1yyc3GCBVZB/03rBtFhYFoS2EruGzOWs/5Q0grgtpwS/DScdRAm8wB8mYEBhY/RKJWF6B2g==", "dev": true, "requires": { - "util": "^0.12.0", - "web3-core-helpers": "1.8.1", - "web3-providers-http": "1.8.1", - "web3-providers-ipc": "1.8.1", - "web3-providers-ws": "1.8.1" + "util": "^0.12.5", + "web3-core-helpers": "1.8.2", + "web3-providers-http": "1.8.2", + "web3-providers-ipc": "1.8.2", + "web3-providers-ws": "1.8.2" } }, "web3-core-subscriptions": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.8.1.tgz", - "integrity": "sha512-bmCMq5OeA3E2vZUh8Js1HcJbhwtsE+yeMqGC4oIZB3XsL5SLqyKLB/pU+qUYqQ9o4GdcrFTDPhPg1bgvf7p1Pw==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.8.2.tgz", + "integrity": "sha512-vXQogHDmAIQcKpXvGiMddBUeP9lnKgYF64+yQJhPNE5PnWr1sAibXuIPV7mIPihpFr/n/DORRj6Wh1pUv9zaTw==", "dev": true, "requires": { "eventemitter3": "4.0.4", - "web3-core-helpers": "1.8.1" + "web3-core-helpers": "1.8.2" } }, "web3-eth": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.8.1.tgz", - "integrity": "sha512-LgyzbhFqiFRd8M8sBXoFN4ztzOnkeckl3H/9lH5ek7AdoRMhBg7tYpYRP3E5qkhd/q+yiZmcUgy1AF6NHrC1wg==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.8.2.tgz", + "integrity": "sha512-JoTiWWc4F4TInpbvDUGb0WgDYJsFhuIjJlinc5ByjWD88Gvh+GKLsRjjFdbqe5YtwIGT4NymwoC5LQd1K6u/QQ==", "dev": true, "requires": { - "web3-core": "1.8.1", - "web3-core-helpers": "1.8.1", - "web3-core-method": "1.8.1", - "web3-core-subscriptions": "1.8.1", - "web3-eth-abi": "1.8.1", - "web3-eth-accounts": "1.8.1", - "web3-eth-contract": "1.8.1", - "web3-eth-ens": "1.8.1", - "web3-eth-iban": "1.8.1", - "web3-eth-personal": "1.8.1", - "web3-net": "1.8.1", - "web3-utils": "1.8.1" + "web3-core": "1.8.2", + "web3-core-helpers": "1.8.2", + "web3-core-method": "1.8.2", + "web3-core-subscriptions": "1.8.2", + "web3-eth-abi": "1.8.2", + "web3-eth-accounts": "1.8.2", + "web3-eth-contract": "1.8.2", + "web3-eth-ens": "1.8.2", + "web3-eth-iban": "1.8.2", + "web3-eth-personal": "1.8.2", + "web3-net": "1.8.2", + "web3-utils": "1.8.2" } }, "web3-eth-abi": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.8.1.tgz", - "integrity": "sha512-0mZvCRTIG0UhDhJwNQJgJxu4b4DyIpuMA0GTfqxqeuqzX4Q/ZvmoNurw0ExTfXaGPP82UUmmdkRi6FdZOx+C6w==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.8.2.tgz", + "integrity": "sha512-Om9g3kaRNjqiNPAgKwGT16y+ZwtBzRe4ZJFGjLiSs6v5I7TPNF+rRMWuKnR6jq0azQZDj6rblvKFMA49/k48Og==", "dev": true, "requires": { "@ethersproject/abi": "^5.6.3", - "web3-utils": "1.8.1" + "web3-utils": "1.8.2" } }, "web3-eth-accounts": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.8.1.tgz", - "integrity": "sha512-mgzxSYgN54/NsOFBO1Fq1KkXp1S5KlBvI/DlgvajU72rupoFMq6Cu6Yp9GUaZ/w2ij9PzEJuFJk174XwtfMCmg==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.8.2.tgz", + "integrity": "sha512-c367Ij63VCz9YdyjiHHWLFtN85l6QghgwMQH2B1eM/p9Y5lTlTX7t/Eg/8+f1yoIStXbk2w/PYM2lk+IkbqdLA==", "dev": true, "requires": { "@ethereumjs/common": "2.5.0", "@ethereumjs/tx": "3.3.2", - "crypto-browserify": "3.12.0", "eth-lib": "0.2.8", - "ethereumjs-util": "^7.0.10", + "ethereumjs-util": "^7.1.5", "scrypt-js": "^3.0.1", "uuid": "^9.0.0", - "web3-core": "1.8.1", - "web3-core-helpers": "1.8.1", - "web3-core-method": "1.8.1", - "web3-utils": "1.8.1" + "web3-core": "1.8.2", + "web3-core-helpers": "1.8.2", + "web3-core-method": "1.8.2", + "web3-utils": "1.8.2" }, "dependencies": { "eth-lib": { @@ -28560,45 +26422,45 @@ } }, "web3-eth-contract": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.8.1.tgz", - "integrity": "sha512-1wphnl+/xwCE2io44JKnN+ti3oa47BKRiVzvWd42icwRbcpFfRxH9QH+aQX3u8VZIISNH7dAkTWpGIIJgGFTmg==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.8.2.tgz", + "integrity": "sha512-ID5A25tHTSBNwOPjiXSVzxruz006ULRIDbzWTYIFTp7NJ7vXu/kynKK2ag/ObuTqBpMbobP8nXcA9b5EDkIdQA==", "dev": true, "requires": { "@types/bn.js": "^5.1.0", - "web3-core": "1.8.1", - "web3-core-helpers": "1.8.1", - "web3-core-method": "1.8.1", - "web3-core-promievent": "1.8.1", - "web3-core-subscriptions": "1.8.1", - "web3-eth-abi": "1.8.1", - "web3-utils": "1.8.1" + "web3-core": "1.8.2", + "web3-core-helpers": "1.8.2", + "web3-core-method": "1.8.2", + "web3-core-promievent": "1.8.2", + "web3-core-subscriptions": "1.8.2", + "web3-eth-abi": "1.8.2", + "web3-utils": "1.8.2" } }, "web3-eth-ens": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.8.1.tgz", - "integrity": "sha512-FT8xTI9uN8RxeBQa/W8pLa2aoFh4+EE34w7W2271LICKzla1dtLyb6XSdn48vsUcPmhWsTVk9mO9RTU0l4LGQQ==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.8.2.tgz", + "integrity": "sha512-PWph7C/CnqdWuu1+SH4U4zdrK4t2HNt0I4XzPYFdv9ugE8EuojselioPQXsVGvjql+Nt3jDLvQvggPqlMbvwRw==", "dev": true, "requires": { "content-hash": "^2.5.2", "eth-ens-namehash": "2.0.8", - "web3-core": "1.8.1", - "web3-core-helpers": "1.8.1", - "web3-core-promievent": "1.8.1", - "web3-eth-abi": "1.8.1", - "web3-eth-contract": "1.8.1", - "web3-utils": "1.8.1" + "web3-core": "1.8.2", + "web3-core-helpers": "1.8.2", + "web3-core-promievent": "1.8.2", + "web3-eth-abi": "1.8.2", + "web3-eth-contract": "1.8.2", + "web3-utils": "1.8.2" } }, "web3-eth-iban": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.8.1.tgz", - "integrity": "sha512-DomoQBfvIdtM08RyMGkMVBOH0vpOIxSSQ+jukWk/EkMLGMWJtXw/K2c2uHAeq3L/VPWNB7zXV2DUEGV/lNE2Dg==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.8.2.tgz", + "integrity": "sha512-h3vNblDWkWMuYx93Q27TAJz6lhzpP93EiC3+45D6xoz983p6si773vntoQ+H+5aZhwglBtoiBzdh7PSSOnP/xQ==", "dev": true, "requires": { "bn.js": "^5.2.1", - "web3-utils": "1.8.1" + "web3-utils": "1.8.2" }, "dependencies": { "bn.js": { @@ -28610,87 +26472,79 @@ } }, "web3-eth-personal": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.8.1.tgz", - "integrity": "sha512-myIYMvj7SDIoV9vE5BkVdon3pya1WinaXItugoii2VoTcQNPOtBxmYVH+XS5ErzCJlnxzphpQrkywyY64bbbCA==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.8.2.tgz", + "integrity": "sha512-Vg4HfwCr7doiUF/RC+Jz0wT4+cYaXcOWMAW2AHIjHX6Z7Xwa8nrURIeQgeEE62qcEHAzajyAdB1u6bJyTfuCXw==", "dev": true, "requires": { "@types/node": "^12.12.6", - "web3-core": "1.8.1", - "web3-core-helpers": "1.8.1", - "web3-core-method": "1.8.1", - "web3-net": "1.8.1", - "web3-utils": "1.8.1" - }, - "dependencies": { - "@types/node": { - "version": "12.20.55", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", - "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", - "dev": true - } + "web3-core": "1.8.2", + "web3-core-helpers": "1.8.2", + "web3-core-method": "1.8.2", + "web3-net": "1.8.2", + "web3-utils": "1.8.2" } }, "web3-net": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.8.1.tgz", - "integrity": "sha512-LyEJAwogdFo0UAXZqoSJGFjopdt+kLw0P00FSZn2yszbgcoI7EwC+nXiOsEe12xz4LqpYLOtbR7+gxgiTVjjHQ==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.8.2.tgz", + "integrity": "sha512-1itkDMGmbgb83Dg9nporFes9/fxsU7smJ3oRXlFkg4ZHn8YJyP1MSQFPJWWwSc+GrcCFt4O5IrUTvEkHqE3xag==", "dev": true, "requires": { - "web3-core": "1.8.1", - "web3-core-method": "1.8.1", - "web3-utils": "1.8.1" + "web3-core": "1.8.2", + "web3-core-method": "1.8.2", + "web3-utils": "1.8.2" } }, "web3-providers-http": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.8.1.tgz", - "integrity": "sha512-1Zyts4O9W/UNEPkp+jyL19Jc3D15S4yp8xuLTjVhcUEAlHo24NDWEKxtZGUuHk4HrKL2gp8OlsDbJ7MM+ESDgg==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.8.2.tgz", + "integrity": "sha512-2xY94IIEQd16+b+vIBF4IC1p7GVaz9q4EUFscvMUjtEq4ru4Atdzjs9GP+jmcoo49p70II0UV3bqQcz0TQfVyQ==", "dev": true, "requires": { "abortcontroller-polyfill": "^1.7.3", "cross-fetch": "^3.1.4", "es6-promise": "^4.2.8", - "web3-core-helpers": "1.8.1" + "web3-core-helpers": "1.8.2" } }, "web3-providers-ipc": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.8.1.tgz", - "integrity": "sha512-nw/W5nclvi+P2z2dYkLWReKLnocStflWqFl+qjtv0xn3MrUTyXMzSF0+61i77+16xFsTgzo4wS/NWIOVkR0EFA==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.8.2.tgz", + "integrity": "sha512-p6fqKVGFg+WiXGHWnB1hu43PbvPkDHTz4RgoEzbXugv5rtv5zfYLqm8Ba6lrJOS5ks9kGKR21a0y3NzE3u7V4w==", "dev": true, "requires": { "oboe": "2.1.5", - "web3-core-helpers": "1.8.1" + "web3-core-helpers": "1.8.2" } }, "web3-providers-ws": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.8.1.tgz", - "integrity": "sha512-TNefIDAMpdx57+YdWpYZ/xdofS0P+FfKaDYXhn24ie/tH9G+AB+UBSOKnjN0KSadcRSCMBwGPRiEmNHPavZdsA==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.8.2.tgz", + "integrity": "sha512-3s/4K+wHgbiN+Zrp9YjMq2eqAF6QGABw7wFftPdx+m5hWImV27/MoIx57c6HffNRqZXmCHnfWWFCNHHsi7wXnA==", "dev": true, "requires": { "eventemitter3": "4.0.4", - "web3-core-helpers": "1.8.1", + "web3-core-helpers": "1.8.2", "websocket": "^1.0.32" } }, "web3-shh": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.8.1.tgz", - "integrity": "sha512-sqHgarnfcY2Qt3PYS4R6YveHrDy7hmL09yeLLHHCI+RKirmjLVqV0rc5LJWUtlbYI+kDoa5gbgde489M9ZAC0g==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.8.2.tgz", + "integrity": "sha512-uZ+3MAoNcaJsXXNCDnizKJ5viBNeHOFYsCbFhV755Uu52FswzTOw6DtE7yK9nYXMtIhiSgi7nwl1RYzP8pystw==", "dev": true, "requires": { - "web3-core": "1.8.1", - "web3-core-method": "1.8.1", - "web3-core-subscriptions": "1.8.1", - "web3-net": "1.8.1" + "web3-core": "1.8.2", + "web3-core-method": "1.8.2", + "web3-core-subscriptions": "1.8.2", + "web3-net": "1.8.2" } }, "web3-utils": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.8.1.tgz", - "integrity": "sha512-LgnM9p6V7rHHUGfpMZod+NST8cRfGzJ1BTXAyNo7A9cJX9LczBfSRxJp+U/GInYe9mby40t3v22AJdlELibnsQ==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.8.2.tgz", + "integrity": "sha512-v7j6xhfLQfY7xQDrUP0BKbaNrmZ2/+egbqP9q3KYmOiPpnvAfol+32slgL0WX/5n8VPvKCK5EZ1HGrAVICSToA==", "dev": true, "requires": { "bn.js": "^5.2.1", @@ -28859,6 +26713,30 @@ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -28893,15 +26771,6 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, - "write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", - "dev": true, - "requires": { - "mkdirp": "^0.5.1" - } - }, "ws": { "version": "7.5.9", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", @@ -28976,9 +26845,9 @@ "dev": true }, "yargs": { - "version": "17.6.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", - "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", "dev": true, "requires": { "cliui": "^8.0.1", @@ -29031,10 +26900,22 @@ } }, "yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + } + } }, "yargs-unparser": { "version": "2.0.0", @@ -29053,6 +26934,18 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true + }, + "decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true + }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true } } }, From 8b47e96af1f3fe06fb581820bbb28d51a0abd4f6 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Fri, 24 Feb 2023 21:29:49 +0100 Subject: [PATCH 059/133] Add SafeERC20.forceApprove() (#4067) --- .changeset/small-terms-sleep.md | 5 + .../mocks/token/ERC20ForceApproveMock.sol | 13 ++ contracts/mocks/token/ERC20NoReturnMock.sol | 31 ++-- .../mocks/token/ERC20PermitNoRevertMock.sol | 4 +- .../mocks/token/ERC20ReturnFalseMock.sol | 18 +- contracts/mocks/token/ERC20ReturnTrueMock.sol | 27 --- contracts/token/ERC20/utils/SafeERC20.sol | 64 ++++++- package-lock.json | 2 +- package.json | 2 +- test/token/ERC20/utils/SafeERC20.test.js | 164 +++++++++++++----- 10 files changed, 226 insertions(+), 104 deletions(-) create mode 100644 .changeset/small-terms-sleep.md create mode 100644 contracts/mocks/token/ERC20ForceApproveMock.sol delete mode 100644 contracts/mocks/token/ERC20ReturnTrueMock.sol diff --git a/.changeset/small-terms-sleep.md b/.changeset/small-terms-sleep.md new file mode 100644 index 000000000..ed184a1c4 --- /dev/null +++ b/.changeset/small-terms-sleep.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': minor +--- + +`SafeERC20`: Add a `forceApprove` function to improve compatibility with tokens behaving like USDT. diff --git a/contracts/mocks/token/ERC20ForceApproveMock.sol b/contracts/mocks/token/ERC20ForceApproveMock.sol new file mode 100644 index 000000000..955224bcf --- /dev/null +++ b/contracts/mocks/token/ERC20ForceApproveMock.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../token/ERC20/ERC20.sol"; + +// contract that replicate USDT (0xdac17f958d2ee523a2206206994597c13d831ec7) approval beavior +abstract contract ERC20ForceApproveMock is ERC20 { + function approve(address spender, uint256 amount) public virtual override returns (bool) { + require(amount == 0 || allowance(msg.sender, spender) == 0, "USDT approval failure"); + return super.approve(spender, amount); + } +} diff --git a/contracts/mocks/token/ERC20NoReturnMock.sol b/contracts/mocks/token/ERC20NoReturnMock.sol index 023dab2cb..348c0d6bb 100644 --- a/contracts/mocks/token/ERC20NoReturnMock.sol +++ b/contracts/mocks/token/ERC20NoReturnMock.sol @@ -2,20 +2,27 @@ pragma solidity ^0.8.0; -contract ERC20NoReturnMock { - mapping(address => uint256) private _allowances; +import "../../token/ERC20/ERC20.sol"; - function transfer(address, uint256) public {} - - function transferFrom(address, address, uint256) public {} - - function approve(address, uint256) public {} - - function setAllowance(address account, uint256 allowance_) public { - _allowances[account] = allowance_; +abstract contract ERC20NoReturnMock is ERC20 { + function transfer(address to, uint256 amount) public override returns (bool) { + super.transfer(to, amount); + assembly { + return(0, 0) + } } - function allowance(address owner, address) public view returns (uint256) { - return _allowances[owner]; + function transferFrom(address from, address to, uint256 amount) public override returns (bool) { + super.transferFrom(from, to, amount); + assembly { + return(0, 0) + } + } + + function approve(address spender, uint256 amount) public override returns (bool) { + super.approve(spender, amount); + assembly { + return(0, 0) + } } } diff --git a/contracts/mocks/token/ERC20PermitNoRevertMock.sol b/contracts/mocks/token/ERC20PermitNoRevertMock.sol index 2b6e2503b..2176c51ae 100644 --- a/contracts/mocks/token/ERC20PermitNoRevertMock.sol +++ b/contracts/mocks/token/ERC20PermitNoRevertMock.sol @@ -5,9 +5,7 @@ pragma solidity ^0.8.0; import "../../token/ERC20/ERC20.sol"; import "../../token/ERC20/extensions/draft-ERC20Permit.sol"; -contract ERC20PermitNoRevertMock is ERC20, ERC20Permit { - constructor() ERC20("ERC20PermitNoRevertMock", "ERC20PermitNoRevertMock") ERC20Permit("ERC20PermitNoRevertMock") {} - +abstract contract ERC20PermitNoRevertMock is ERC20Permit { function permitThatMayRevert( address owner, address spender, diff --git a/contracts/mocks/token/ERC20ReturnFalseMock.sol b/contracts/mocks/token/ERC20ReturnFalseMock.sol index 3f8f64037..c4dc6921f 100644 --- a/contracts/mocks/token/ERC20ReturnFalseMock.sol +++ b/contracts/mocks/token/ERC20ReturnFalseMock.sol @@ -2,26 +2,18 @@ pragma solidity ^0.8.0; -contract ERC20ReturnFalseMock { - mapping(address => uint256) private _allowances; +import "../../token/ERC20/ERC20.sol"; - function transfer(address, uint256) public pure returns (bool) { +abstract contract ERC20ReturnFalseMock is ERC20 { + function transfer(address, uint256) public pure override returns (bool) { return false; } - function transferFrom(address, address, uint256) public pure returns (bool) { + function transferFrom(address, address, uint256) public pure override returns (bool) { return false; } - function approve(address, uint256) public pure returns (bool) { + function approve(address, uint256) public pure override returns (bool) { return false; } - - function setAllowance(address account, uint256 allowance_) public { - _allowances[account] = allowance_; - } - - function allowance(address owner, address) public view returns (uint256) { - return _allowances[owner]; - } } diff --git a/contracts/mocks/token/ERC20ReturnTrueMock.sol b/contracts/mocks/token/ERC20ReturnTrueMock.sol deleted file mode 100644 index 8953aad64..000000000 --- a/contracts/mocks/token/ERC20ReturnTrueMock.sol +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.0; - -contract ERC20ReturnTrueMock { - mapping(address => uint256) private _allowances; - - function transfer(address, uint256) public pure returns (bool) { - return true; - } - - function transferFrom(address, address, uint256) public pure returns (bool) { - return true; - } - - function approve(address, uint256) public pure returns (bool) { - return true; - } - - function setAllowance(address account, uint256 allowance_) public { - _allowances[account] = allowance_; - } - - function allowance(address owner, address) public view returns (uint256) { - return _allowances[owner]; - } -} diff --git a/contracts/token/ERC20/utils/SafeERC20.sol b/contracts/token/ERC20/utils/SafeERC20.sol index 028711ddf..2f76386d5 100644 --- a/contracts/token/ERC20/utils/SafeERC20.sol +++ b/contracts/token/ERC20/utils/SafeERC20.sol @@ -19,10 +19,18 @@ import "../../../utils/Address.sol"; library SafeERC20 { using Address for address; + /** + * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, + * non-reverting calls are assumed to be successful. + */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } + /** + * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the + * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. + */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } @@ -45,20 +53,45 @@ library SafeERC20 { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } + /** + * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, + * non-reverting calls are assumed to be successful. + */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { - uint256 newAllowance = token.allowance(address(this), spender) + value; - _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); + uint256 oldAllowance = token.allowance(address(this), spender); + _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value)); } + /** + * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value, + * non-reverting calls are assumed to be successful. + */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); - uint256 newAllowance = oldAllowance - value; - _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); + _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); } } + /** + * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, + * non-reverting calls are assumed to be successful. Compatible with tokens that require the approval to be set to + * 0 before setting it to a non-zero value. + */ + function forceApprove(IERC20 token, address spender, uint256 value) internal { + bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value); + + if (!_callOptionalReturnBool(token, approvalCall)) { + _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); + _callOptionalReturn(token, approvalCall); + } + } + + /** + * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`. + * Revert on invalid signature. + */ function safePermit( IERC20Permit token, address owner, @@ -87,9 +120,24 @@ library SafeERC20 { // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); - if (returndata.length > 0) { - // Return data is optional - require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); - } + require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); + } + + /** + * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement + * on the return value: the return value is optional (but if data is returned, it must not be false). + * @param token The token targeted by the call. + * @param data The call data (encoded using abi.encode or one of its variants). + * + * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. + */ + function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { + // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since + // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false + // and not revert is the subcall reverts. + + (bool success, bytes memory returndata) = address(token).call(data); + return + success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token)); } } diff --git a/package-lock.json b/package-lock.json index 87fd3a795..fc3918807 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,7 +31,7 @@ "glob": "^8.0.3", "graphlib": "^2.1.8", "hardhat": "^2.9.1", - "hardhat-exposed": "^0.3.1", + "hardhat-exposed": "^0.3.2", "hardhat-gas-reporter": "^1.0.4", "hardhat-ignore-warnings": "^0.2.0", "keccak256": "^1.0.2", diff --git a/package.json b/package.json index 66d44888a..f0ee95ab0 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "glob": "^8.0.3", "graphlib": "^2.1.8", "hardhat": "^2.9.1", - "hardhat-exposed": "^0.3.1", + "hardhat-exposed": "^0.3.2", "hardhat-gas-reporter": "^1.0.4", "hardhat-ignore-warnings": "^0.2.0", "keccak256": "^1.0.2", diff --git a/test/token/ERC20/utils/SafeERC20.test.js b/test/token/ERC20/utils/SafeERC20.test.js index a6b10fae3..d4981dd30 100644 --- a/test/token/ERC20/utils/SafeERC20.test.js +++ b/test/token/ERC20/utils/SafeERC20.test.js @@ -1,10 +1,11 @@ -const { constants, expectRevert } = require('@openzeppelin/test-helpers'); +const { constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); const SafeERC20 = artifacts.require('$SafeERC20'); -const ERC20ReturnFalseMock = artifacts.require('ERC20ReturnFalseMock'); -const ERC20ReturnTrueMock = artifacts.require('ERC20ReturnTrueMock'); -const ERC20NoReturnMock = artifacts.require('ERC20NoReturnMock'); -const ERC20PermitNoRevertMock = artifacts.require('ERC20PermitNoRevertMock'); +const ERC20ReturnFalseMock = artifacts.require('$ERC20ReturnFalseMock'); +const ERC20ReturnTrueMock = artifacts.require('$ERC20'); // default implementation returns true +const ERC20NoReturnMock = artifacts.require('$ERC20NoReturnMock'); +const ERC20PermitNoRevertMock = artifacts.require('$ERC20PermitNoRevertMock'); +const ERC20ForceApproveMock = artifacts.require('$ERC20ForceApproveMock'); const { getDomain, domainType, Permit } = require('../../../helpers/eip712'); @@ -12,6 +13,9 @@ const { fromRpcSig } = require('ethereumjs-util'); const ethSigUtil = require('eth-sig-util'); const Wallet = require('ethereumjs-wallet').default; +const name = 'ERC20Mock'; +const symbol = 'ERC20Mock'; + contract('SafeERC20', function (accounts) { const [hasNoCode] = accounts; @@ -24,31 +28,31 @@ contract('SafeERC20', function (accounts) { this.token = { address: hasNoCode }; }); - shouldRevertOnAllCalls('Address: call to non-contract'); + shouldRevertOnAllCalls(accounts, 'Address: call to non-contract'); }); describe('with token that returns false on all calls', function () { beforeEach(async function () { - this.token = await ERC20ReturnFalseMock.new(); + this.token = await ERC20ReturnFalseMock.new(name, symbol); }); - shouldRevertOnAllCalls('SafeERC20: ERC20 operation did not succeed'); + shouldRevertOnAllCalls(accounts, 'SafeERC20: ERC20 operation did not succeed'); }); describe('with token that returns true on all calls', function () { beforeEach(async function () { - this.token = await ERC20ReturnTrueMock.new(); + this.token = await ERC20ReturnTrueMock.new(name, symbol); }); - shouldOnlyRevertOnErrors(); + shouldOnlyRevertOnErrors(accounts); }); describe('with token that returns no boolean values', function () { beforeEach(async function () { - this.token = await ERC20NoReturnMock.new(); + this.token = await ERC20NoReturnMock.new(name, symbol); }); - shouldOnlyRevertOnErrors(); + shouldOnlyRevertOnErrors(accounts); }); describe("with token that doesn't revert on invalid permit", function () { @@ -57,7 +61,7 @@ contract('SafeERC20', function (accounts) { const spender = hasNoCode; beforeEach(async function () { - this.token = await ERC20PermitNoRevertMock.new(); + this.token = await ERC20PermitNoRevertMock.new(name, symbol, name); this.data = await getDomain(this.token).then(domain => ({ primaryType: 'Permit', @@ -165,65 +169,134 @@ contract('SafeERC20', function (accounts) { ); }); }); + + describe('with usdt approval beaviour', function () { + const spender = hasNoCode; + + beforeEach(async function () { + this.token = await ERC20ForceApproveMock.new(name, symbol); + }); + + describe('with initial approval', function () { + beforeEach(async function () { + await this.token.$_approve(this.mock.address, spender, 100); + }); + + it('safeApprove fails to update approval to non-zero', async function () { + await expectRevert( + this.mock.$safeApprove(this.token.address, spender, 200), + 'SafeERC20: approve from non-zero to non-zero allowance', + ); + }); + + it('safeApprove can update approval to zero', async function () { + await this.mock.$safeApprove(this.token.address, spender, 0); + }); + + it('safeApprove can increase approval', async function () { + await expectRevert(this.mock.$safeIncreaseAllowance(this.token.address, spender, 10), 'USDT approval failure'); + }); + + it('safeApprove can decrease approval', async function () { + await expectRevert(this.mock.$safeDecreaseAllowance(this.token.address, spender, 10), 'USDT approval failure'); + }); + + it('forceApprove works', async function () { + await this.mock.$forceApprove(this.token.address, spender, 200); + }); + }); + }); }); -function shouldRevertOnAllCalls(reason) { +function shouldRevertOnAllCalls([receiver, spender], reason) { it('reverts on transfer', async function () { - await expectRevert(this.mock.$safeTransfer(this.token.address, constants.ZERO_ADDRESS, 0), reason); + await expectRevert(this.mock.$safeTransfer(this.token.address, receiver, 0), reason); }); it('reverts on transferFrom', async function () { - await expectRevert( - this.mock.$safeTransferFrom(this.token.address, this.mock.address, constants.ZERO_ADDRESS, 0), - reason, - ); + await expectRevert(this.mock.$safeTransferFrom(this.token.address, this.mock.address, receiver, 0), reason); }); it('reverts on approve', async function () { - await expectRevert(this.mock.$safeApprove(this.token.address, constants.ZERO_ADDRESS, 0), reason); + await expectRevert(this.mock.$safeApprove(this.token.address, spender, 0), reason); }); it('reverts on increaseAllowance', async function () { // [TODO] make sure it's reverting for the right reason - await expectRevert.unspecified(this.mock.$safeIncreaseAllowance(this.token.address, constants.ZERO_ADDRESS, 0)); + await expectRevert.unspecified(this.mock.$safeIncreaseAllowance(this.token.address, spender, 0)); }); it('reverts on decreaseAllowance', async function () { // [TODO] make sure it's reverting for the right reason - await expectRevert.unspecified(this.mock.$safeDecreaseAllowance(this.token.address, constants.ZERO_ADDRESS, 0)); + await expectRevert.unspecified(this.mock.$safeDecreaseAllowance(this.token.address, spender, 0)); + }); + + it('reverts on forceApprove', async function () { + await expectRevert(this.mock.$forceApprove(this.token.address, spender, 0), reason); }); } -function shouldOnlyRevertOnErrors() { - it("doesn't revert on transfer", async function () { - await this.mock.$safeTransfer(this.token.address, constants.ZERO_ADDRESS, 0); - }); +function shouldOnlyRevertOnErrors([owner, receiver, spender]) { + describe('transfers', function () { + beforeEach(async function () { + await this.token.$_mint(owner, 100); + await this.token.$_mint(this.mock.address, 100); + await this.token.approve(this.mock.address, constants.MAX_UINT256, { from: owner }); + }); - it("doesn't revert on transferFrom", async function () { - await this.mock.$safeTransferFrom(this.token.address, this.mock.address, constants.ZERO_ADDRESS, 0); + it("doesn't revert on transfer", async function () { + const { tx } = await this.mock.$safeTransfer(this.token.address, receiver, 10); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.mock.address, + to: receiver, + value: '10', + }); + }); + + it("doesn't revert on transferFrom", async function () { + const { tx } = await this.mock.$safeTransferFrom(this.token.address, owner, receiver, 10); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: owner, + to: receiver, + value: '10', + }); + }); }); describe('approvals', function () { context('with zero allowance', function () { beforeEach(async function () { - await this.token.setAllowance(this.mock.address, 0); + await this.token.$_approve(this.mock.address, spender, 0); }); it("doesn't revert when approving a non-zero allowance", async function () { - await this.mock.$safeApprove(this.token.address, constants.ZERO_ADDRESS, 100); + await this.mock.$safeApprove(this.token.address, spender, 100); + expect(await this.token.allowance(this.mock.address, spender)).to.be.bignumber.equal('100'); }); it("doesn't revert when approving a zero allowance", async function () { - await this.mock.$safeApprove(this.token.address, constants.ZERO_ADDRESS, 0); + await this.mock.$safeApprove(this.token.address, spender, 0); + expect(await this.token.allowance(this.mock.address, spender)).to.be.bignumber.equal('0'); + }); + + it("doesn't revert when force approving a non-zero allowance", async function () { + await this.mock.$forceApprove(this.token.address, spender, 100); + expect(await this.token.allowance(this.mock.address, spender)).to.be.bignumber.equal('100'); + }); + + it("doesn't revert when force approving a zero allowance", async function () { + await this.mock.$forceApprove(this.token.address, spender, 0); + expect(await this.token.allowance(this.mock.address, spender)).to.be.bignumber.equal('0'); }); it("doesn't revert when increasing the allowance", async function () { - await this.mock.$safeIncreaseAllowance(this.token.address, constants.ZERO_ADDRESS, 10); + await this.mock.$safeIncreaseAllowance(this.token.address, spender, 10); + expect(await this.token.allowance(this.mock.address, spender)).to.be.bignumber.equal('10'); }); it('reverts when decreasing the allowance', async function () { await expectRevert( - this.mock.$safeDecreaseAllowance(this.token.address, constants.ZERO_ADDRESS, 10), + this.mock.$safeDecreaseAllowance(this.token.address, spender, 10), 'SafeERC20: decreased allowance below zero', ); }); @@ -231,31 +304,44 @@ function shouldOnlyRevertOnErrors() { context('with non-zero allowance', function () { beforeEach(async function () { - await this.token.setAllowance(this.mock.address, 100); + await this.token.$_approve(this.mock.address, spender, 100); }); it('reverts when approving a non-zero allowance', async function () { await expectRevert( - this.mock.$safeApprove(this.token.address, constants.ZERO_ADDRESS, 20), + this.mock.$safeApprove(this.token.address, spender, 20), 'SafeERC20: approve from non-zero to non-zero allowance', ); }); it("doesn't revert when approving a zero allowance", async function () { - await this.mock.$safeApprove(this.token.address, constants.ZERO_ADDRESS, 0); + await this.mock.$safeApprove(this.token.address, spender, 0); + expect(await this.token.allowance(this.mock.address, spender)).to.be.bignumber.equal('0'); + }); + + it("doesn't revert when force approving a non-zero allowance", async function () { + await this.mock.$forceApprove(this.token.address, spender, 20); + expect(await this.token.allowance(this.mock.address, spender)).to.be.bignumber.equal('20'); + }); + + it("doesn't revert when force approving a zero allowance", async function () { + await this.mock.$forceApprove(this.token.address, spender, 0); + expect(await this.token.allowance(this.mock.address, spender)).to.be.bignumber.equal('0'); }); it("doesn't revert when increasing the allowance", async function () { - await this.mock.$safeIncreaseAllowance(this.token.address, constants.ZERO_ADDRESS, 10); + await this.mock.$safeIncreaseAllowance(this.token.address, spender, 10); + expect(await this.token.allowance(this.mock.address, spender)).to.be.bignumber.equal('110'); }); it("doesn't revert when decreasing the allowance to a positive value", async function () { - await this.mock.$safeDecreaseAllowance(this.token.address, constants.ZERO_ADDRESS, 50); + await this.mock.$safeDecreaseAllowance(this.token.address, spender, 50); + expect(await this.token.allowance(this.mock.address, spender)).to.be.bignumber.equal('50'); }); it('reverts when decreasing the allowance to a negative value', async function () { await expectRevert( - this.mock.$safeDecreaseAllowance(this.token.address, constants.ZERO_ADDRESS, 200), + this.mock.$safeDecreaseAllowance(this.token.address, spender, 200), 'SafeERC20: decreased allowance below zero', ); }); From 3f3774c5df70a7d2399810872056bb5338a09b4c Mon Sep 17 00:00:00 2001 From: Vittorio Minacori Date: Fri, 24 Feb 2023 22:28:37 +0100 Subject: [PATCH 060/133] Improve ERC1363 documentation (#3993) Co-authored-by: Francisco --- contracts/interfaces/IERC1363.sol | 31 ++++++++++++++--------- contracts/interfaces/IERC1363Receiver.sol | 11 +++++--- contracts/interfaces/IERC1363Spender.sol | 11 +++++--- 3 files changed, 33 insertions(+), 20 deletions(-) diff --git a/contracts/interfaces/IERC1363.sol b/contracts/interfaces/IERC1363.sol index 1517197fe..63d87b962 100644 --- a/contracts/interfaces/IERC1363.sol +++ b/contracts/interfaces/IERC1363.sol @@ -6,6 +6,13 @@ pragma solidity ^0.8.0; import "./IERC20.sol"; import "./IERC165.sol"; +/** + * @dev Interface of an ERC1363 compliant contract, as defined in the + * https://eips.ethereum.org/EIPS/eip-1363[EIP]. + * + * Defines a interface for ERC20 tokens that supports executing recipient + * code after `transfer` or `transferFrom`, or spender code after `approve`. + */ interface IERC1363 is IERC165, IERC20 { /* * Note: the ERC-165 identifier for this interface is 0xb0202a11. @@ -21,53 +28,53 @@ interface IERC1363 is IERC165, IERC20 { /** * @dev Transfer tokens from `msg.sender` to another address and then call `onTransferReceived` on receiver * @param to address The address which you want to transfer to - * @param value uint256 The amount of tokens to be transferred + * @param amount uint256 The amount of tokens to be transferred * @return true unless throwing */ - function transferAndCall(address to, uint256 value) external returns (bool); + function transferAndCall(address to, uint256 amount) external returns (bool); /** * @dev Transfer tokens from `msg.sender` to another address and then call `onTransferReceived` on receiver * @param to address The address which you want to transfer to - * @param value uint256 The amount of tokens to be transferred + * @param amount uint256 The amount of tokens to be transferred * @param data bytes Additional data with no specified format, sent in call to `to` * @return true unless throwing */ - function transferAndCall(address to, uint256 value, bytes memory data) external returns (bool); + function transferAndCall(address to, uint256 amount, bytes memory data) external returns (bool); /** * @dev Transfer tokens from one address to another and then call `onTransferReceived` on receiver * @param from address The address which you want to send tokens from * @param to address The address which you want to transfer to - * @param value uint256 The amount of tokens to be transferred + * @param amount uint256 The amount of tokens to be transferred * @return true unless throwing */ - function transferFromAndCall(address from, address to, uint256 value) external returns (bool); + function transferFromAndCall(address from, address to, uint256 amount) external returns (bool); /** * @dev Transfer tokens from one address to another and then call `onTransferReceived` on receiver * @param from address The address which you want to send tokens from * @param to address The address which you want to transfer to - * @param value uint256 The amount of tokens to be transferred + * @param amount uint256 The amount of tokens to be transferred * @param data bytes Additional data with no specified format, sent in call to `to` * @return true unless throwing */ - function transferFromAndCall(address from, address to, uint256 value, bytes memory data) external returns (bool); + function transferFromAndCall(address from, address to, uint256 amount, bytes memory data) external returns (bool); /** * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender * and then call `onApprovalReceived` on spender. * @param spender address The address which will spend the funds - * @param value uint256 The amount of tokens to be spent + * @param amount uint256 The amount of tokens to be spent */ - function approveAndCall(address spender, uint256 value) external returns (bool); + function approveAndCall(address spender, uint256 amount) external returns (bool); /** * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender * and then call `onApprovalReceived` on spender. * @param spender address The address which will spend the funds - * @param value uint256 The amount of tokens to be spent + * @param amount uint256 The amount of tokens to be spent * @param data bytes Additional data with no specified format, sent in call to `spender` */ - function approveAndCall(address spender, uint256 value, bytes memory data) external returns (bool); + function approveAndCall(address spender, uint256 amount, bytes memory data) external returns (bool); } diff --git a/contracts/interfaces/IERC1363Receiver.sol b/contracts/interfaces/IERC1363Receiver.sol index bc5eaddb0..f5e7a0c28 100644 --- a/contracts/interfaces/IERC1363Receiver.sol +++ b/contracts/interfaces/IERC1363Receiver.sol @@ -3,6 +3,10 @@ pragma solidity ^0.8.0; +/** + * @dev Interface for any contract that wants to support {IERC1363-transferAndCall} + * or {IERC1363-transferFromAndCall} from {ERC1363} token contracts. + */ interface IERC1363Receiver { /* * Note: the ERC-165 identifier for this interface is 0x88a7ca5c. @@ -18,15 +22,14 @@ interface IERC1363Receiver { * Note: the token contract address is always the message sender. * @param operator address The address which called `transferAndCall` or `transferFromAndCall` function * @param from address The address which are token transferred from - * @param value uint256 The amount of tokens transferred + * @param amount uint256 The amount of tokens transferred * @param data bytes Additional data with no specified format - * @return `bytes4(keccak256("onTransferReceived(address,address,uint256,bytes)"))` - * unless throwing + * @return `bytes4(keccak256("onTransferReceived(address,address,uint256,bytes)"))` unless throwing */ function onTransferReceived( address operator, address from, - uint256 value, + uint256 amount, bytes memory data ) external returns (bytes4); } diff --git a/contracts/interfaces/IERC1363Spender.sol b/contracts/interfaces/IERC1363Spender.sol index 28775e140..16dd5e0fe 100644 --- a/contracts/interfaces/IERC1363Spender.sol +++ b/contracts/interfaces/IERC1363Spender.sol @@ -3,6 +3,10 @@ pragma solidity ^0.8.0; +/** + * @dev Interface for any contract that wants to support {IERC1363-approveAndCall} + * from {ERC1363} token contracts. + */ interface IERC1363Spender { /* * Note: the ERC-165 identifier for this interface is 0x7b04a2d0. @@ -17,10 +21,9 @@ interface IERC1363Spender { * transaction being reverted. * Note: the token contract address is always the message sender. * @param owner address The address which called `approveAndCall` function - * @param value uint256 The amount of tokens to be spent + * @param amount uint256 The amount of tokens to be spent * @param data bytes Additional data with no specified format - * @return `bytes4(keccak256("onApprovalReceived(address,uint256,bytes)"))` - * unless throwing + * @return `bytes4(keccak256("onApprovalReceived(address,uint256,bytes)"))`unless throwing */ - function onApprovalReceived(address owner, uint256 value, bytes memory data) external returns (bytes4); + function onApprovalReceived(address owner, uint256 amount, bytes memory data) external returns (bytes4); } From 2c69f9f9f5d0e59bba030f6eba5495f7a6991162 Mon Sep 17 00:00:00 2001 From: Clayton Rabenda Date: Sat, 25 Feb 2023 05:31:54 +0800 Subject: [PATCH 061/133] Fix comment on ERC777._beforeTokenTransfer (#3982) --- contracts/token/ERC777/ERC777.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/token/ERC777/ERC777.sol b/contracts/token/ERC777/ERC777.sol index 0e5af5d08..aa95b1843 100644 --- a/contracts/token/ERC777/ERC777.sol +++ b/contracts/token/ERC777/ERC777.sol @@ -498,7 +498,7 @@ contract ERC777 is Context, IERC777, IERC20 { /** * @dev Hook that is called before any token transfer. This includes - * calls to {send}, {transfer}, {operatorSend}, minting and burning. + * calls to {send}, {transfer}, {operatorSend}, {transferFrom}, minting and burning. * * Calling conditions: * From dad73159df3d3053c72b5e430fa8164330f18068 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Garc=C3=ADa?= Date: Fri, 24 Feb 2023 14:48:08 -0700 Subject: [PATCH 062/133] Add AccessControlDefaultAdminRules (#4009) Co-authored-by: Hadrien Croubois Co-authored-by: Francisco --- .changeset/silent-dancers-type.md | 5 + contracts/access/AccessControl.sol | 3 +- .../access/AccessControlDefaultAdminRules.sol | 240 +++++++++++++++ .../IAccessControlDefaultAdminRules.sol | 73 +++++ contracts/access/Ownable.sol | 4 +- contracts/access/README.adoc | 2 + contracts/interfaces/README.adoc | 2 + docs/modules/ROOT/pages/access-control.adoc | 2 + .../ROOT/pages/extending-contracts.adoc | 2 + test/access/AccessControl.behavior.js | 284 ++++++++++++++++++ .../AccessControlDefaultAdminRules.test.js | 18 ++ test/access/Ownable.test.js | 10 +- test/access/Ownable2Step.test.js | 22 +- .../SupportsInterface.behavior.js | 9 + 14 files changed, 666 insertions(+), 10 deletions(-) create mode 100644 .changeset/silent-dancers-type.md create mode 100644 contracts/access/AccessControlDefaultAdminRules.sol create mode 100644 contracts/access/IAccessControlDefaultAdminRules.sol create mode 100644 test/access/AccessControlDefaultAdminRules.test.js diff --git a/.changeset/silent-dancers-type.md b/.changeset/silent-dancers-type.md new file mode 100644 index 000000000..74ecf500d --- /dev/null +++ b/.changeset/silent-dancers-type.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': minor +--- + +`AccessControlDefaultAdminRules`: Add an extension of `AccessControl` with additional security rules for the `DEFAULT_ADMIN_ROLE`. diff --git a/contracts/access/AccessControl.sol b/contracts/access/AccessControl.sol index 5f2829e74..3a73de78b 100644 --- a/contracts/access/AccessControl.sol +++ b/contracts/access/AccessControl.sol @@ -44,7 +44,8 @@ import "../utils/introspection/ERC165.sol"; * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure - * accounts that have been granted it. + * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} + * to enforce additional security measures for this role. */ abstract contract AccessControl is Context, IAccessControl, ERC165 { struct RoleData { diff --git a/contracts/access/AccessControlDefaultAdminRules.sol b/contracts/access/AccessControlDefaultAdminRules.sol new file mode 100644 index 000000000..e3bce6b75 --- /dev/null +++ b/contracts/access/AccessControlDefaultAdminRules.sol @@ -0,0 +1,240 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControlDefaultAdminRules.sol) + +pragma solidity ^0.8.0; + +import "./AccessControl.sol"; +import "./IAccessControlDefaultAdminRules.sol"; +import "../utils/math/SafeCast.sol"; +import "../interfaces/IERC5313.sol"; + +/** + * @dev Extension of {AccessControl} that allows specifying special rules to manage + * the `DEFAULT_ADMIN_ROLE` holder, which is a sensitive role with special permissions + * over other roles that may potentially have privileged rights in the system. + * + * If a specific role doesn't have an admin role assigned, the holder of the + * `DEFAULT_ADMIN_ROLE` will have the ability to grant it and revoke it. + * + * This contract implements the following risk mitigations on top of {AccessControl}: + * + * * Only one account holds the `DEFAULT_ADMIN_ROLE` since deployment until it's potentially renounced. + * * Enforce a 2-step process to transfer the `DEFAULT_ADMIN_ROLE` to another account. + * * Enforce a configurable delay between the two steps, with the ability to cancel in between. + * - Even after the timer has passed to avoid locking it forever. + * * It is not possible to use another role to manage the `DEFAULT_ADMIN_ROLE`. + * + * Example usage: + * + * ```solidity + * contract MyToken is AccessControlDefaultAdminRules { + * constructor() AccessControlDefaultAdminRules( + * 3 days, + * msg.sender // Explicit initial `DEFAULT_ADMIN_ROLE` holder + * ) {} + *} + * ``` + * + * NOTE: The `delay` can only be set in the constructor and is fixed thereafter. + * + * _Available since v4.9._ + */ +abstract contract AccessControlDefaultAdminRules is IAccessControlDefaultAdminRules, IERC5313, AccessControl { + uint48 private immutable _defaultAdminDelay; + + address private _currentDefaultAdmin; + address private _pendingDefaultAdmin; + + uint48 private _defaultAdminTransferDelayedUntil; + + /** + * @dev Sets the initial values for {defaultAdminDelay} in seconds and {defaultAdmin}. + * + * The `defaultAdminDelay` value is immutable. It can only be set at the constructor. + */ + constructor(uint48 defaultAdminDelay_, address initialDefaultAdmin) { + _defaultAdminDelay = defaultAdminDelay_; + _grantRole(DEFAULT_ADMIN_ROLE, initialDefaultAdmin); + } + + /** + * @dev See {IERC5313-owner}. + */ + function owner() public view virtual returns (address) { + return defaultAdmin(); + } + + /** + * @inheritdoc IAccessControlDefaultAdminRules + */ + function defaultAdminDelay() public view virtual returns (uint48) { + return _defaultAdminDelay; + } + + /** + * @inheritdoc IAccessControlDefaultAdminRules + */ + function defaultAdmin() public view virtual returns (address) { + return _currentDefaultAdmin; + } + + /** + * @inheritdoc IAccessControlDefaultAdminRules + */ + function pendingDefaultAdmin() public view virtual returns (address) { + return _pendingDefaultAdmin; + } + + /** + * @inheritdoc IAccessControlDefaultAdminRules + */ + function defaultAdminTransferDelayedUntil() public view virtual returns (uint48) { + return _defaultAdminTransferDelayedUntil; + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IAccessControlDefaultAdminRules).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @inheritdoc IAccessControlDefaultAdminRules + */ + function beginDefaultAdminTransfer(address newAdmin) public virtual onlyRole(DEFAULT_ADMIN_ROLE) { + _beginDefaultAdminTransfer(newAdmin); + } + + /** + * @inheritdoc IAccessControlDefaultAdminRules + */ + function acceptDefaultAdminTransfer() public virtual { + require(_msgSender() == pendingDefaultAdmin(), "AccessControl: pending admin must accept"); + _acceptDefaultAdminTransfer(); + } + + /** + * @inheritdoc IAccessControlDefaultAdminRules + */ + function cancelDefaultAdminTransfer() public virtual onlyRole(DEFAULT_ADMIN_ROLE) { + _resetDefaultAdminTransfer(); + } + + /** + * @dev Revokes `role` from the calling account. + * + * For `DEFAULT_ADMIN_ROLE`, only allows renouncing in two steps, so it's required + * that the {defaultAdminTransferDelayedUntil} has passed and the pending default admin is the zero address. + * After its execution, it will not be possible to call `onlyRole(DEFAULT_ADMIN_ROLE)` + * functions. + * + * For other roles, see {AccessControl-renounceRole}. + * + * NOTE: Renouncing `DEFAULT_ADMIN_ROLE` will leave the contract without a defaultAdmin, + * thereby disabling any functionality that is only available to the default admin, and the + * possibility of reassigning a non-administrated role. + */ + function renounceRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) { + if (role == DEFAULT_ADMIN_ROLE) { + require( + pendingDefaultAdmin() == address(0) && _hasDefaultAdminTransferDelayPassed(), + "AccessControl: only can renounce in two delayed steps" + ); + } + super.renounceRole(role, account); + } + + /** + * @dev See {AccessControl-grantRole}. Reverts for `DEFAULT_ADMIN_ROLE`. + */ + function grantRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) { + require(role != DEFAULT_ADMIN_ROLE, "AccessControl: can't directly grant default admin role"); + super.grantRole(role, account); + } + + /** + * @dev See {AccessControl-revokeRole}. Reverts for `DEFAULT_ADMIN_ROLE`. + */ + function revokeRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) { + require(role != DEFAULT_ADMIN_ROLE, "AccessControl: can't directly revoke default admin role"); + super.revokeRole(role, account); + } + + /** + * @dev See {AccessControl-_setRoleAdmin}. Reverts for `DEFAULT_ADMIN_ROLE`. + */ + function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual override { + require(role != DEFAULT_ADMIN_ROLE, "AccessControl: can't violate default admin rules"); + super._setRoleAdmin(role, adminRole); + } + + /** + * @dev Grants `role` to `account`. + * + * For `DEFAULT_ADMIN_ROLE`, it only allows granting if there isn't already a role's holder + * or if the role has been previously renounced. + * + * For other roles, see {AccessControl-renounceRole}. + * + * NOTE: Exposing this function through another mechanism may make the + * `DEFAULT_ADMIN_ROLE` assignable again. Make sure to guarantee this is + * the expected behavior in your implementation. + */ + function _grantRole(bytes32 role, address account) internal virtual override { + if (role == DEFAULT_ADMIN_ROLE) { + require(defaultAdmin() == address(0), "AccessControl: default admin already granted"); + _currentDefaultAdmin = account; + } + super._grantRole(role, account); + } + + /** + * @dev See {acceptDefaultAdminTransfer}. + * + * Internal function without access restriction. + */ + function _acceptDefaultAdminTransfer() internal virtual { + require(_hasDefaultAdminTransferDelayPassed(), "AccessControl: transfer delay not passed"); + _revokeRole(DEFAULT_ADMIN_ROLE, defaultAdmin()); + _grantRole(DEFAULT_ADMIN_ROLE, pendingDefaultAdmin()); + _resetDefaultAdminTransfer(); + } + + /** + * @dev See {beginDefaultAdminTransfer}. + * + * Internal function without access restriction. + */ + function _beginDefaultAdminTransfer(address newAdmin) internal virtual { + _defaultAdminTransferDelayedUntil = SafeCast.toUint48(block.timestamp) + defaultAdminDelay(); + _pendingDefaultAdmin = newAdmin; + emit DefaultAdminRoleChangeStarted(pendingDefaultAdmin(), defaultAdminTransferDelayedUntil()); + } + + /** + * @dev See {AccessControl-_revokeRole}. + */ + function _revokeRole(bytes32 role, address account) internal virtual override { + if (role == DEFAULT_ADMIN_ROLE) { + delete _currentDefaultAdmin; + } + super._revokeRole(role, account); + } + + /** + * @dev Resets the pending default admin and delayed until. + */ + function _resetDefaultAdminTransfer() private { + delete _pendingDefaultAdmin; + delete _defaultAdminTransferDelayedUntil; + } + + /** + * @dev Checks if a {defaultAdminTransferDelayedUntil} has been set and passed. + */ + function _hasDefaultAdminTransferDelayPassed() private view returns (bool) { + uint48 delayedUntil = defaultAdminTransferDelayedUntil(); + return delayedUntil > 0 && delayedUntil < block.timestamp; + } +} diff --git a/contracts/access/IAccessControlDefaultAdminRules.sol b/contracts/access/IAccessControlDefaultAdminRules.sol new file mode 100644 index 000000000..753c7c802 --- /dev/null +++ b/contracts/access/IAccessControlDefaultAdminRules.sol @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.9.0 (access/IAccessControlDefaultAdminRules.sol) + +pragma solidity ^0.8.0; + +import "./IAccessControl.sol"; + +/** + * @dev External interface of AccessControlDefaultAdminRules declared to support ERC165 detection. + * + * _Available since v4.9._ + */ +interface IAccessControlDefaultAdminRules is IAccessControl { + /** + * @dev Emitted when a `DEFAULT_ADMIN_ROLE` transfer is started, setting `newDefaultAdmin` + * as the next default admin, which will have rights to claim the `DEFAULT_ADMIN_ROLE` + * after `defaultAdminTransferDelayedUntil` has passed. + */ + event DefaultAdminRoleChangeStarted(address indexed newDefaultAdmin, uint48 defaultAdminTransferDelayedUntil); + + /** + * @dev Returns the delay between each `DEFAULT_ADMIN_ROLE` transfer. + */ + function defaultAdminDelay() external view returns (uint48); + + /** + * @dev Returns the address of the current `DEFAULT_ADMIN_ROLE` holder. + */ + function defaultAdmin() external view returns (address); + + /** + * @dev Returns the address of the pending `DEFAULT_ADMIN_ROLE` holder. + */ + function pendingDefaultAdmin() external view returns (address); + + /** + * @dev Returns the timestamp after which the pending default admin can claim the `DEFAULT_ADMIN_ROLE`. + */ + function defaultAdminTransferDelayedUntil() external view returns (uint48); + + /** + * @dev Starts a `DEFAULT_ADMIN_ROLE` transfer by setting a pending default admin + * and a timer to pass. + * + * Requirements: + * + * - Only can be called by the current `DEFAULT_ADMIN_ROLE` holder. + * + * Emits a {DefaultAdminRoleChangeStarted}. + */ + function beginDefaultAdminTransfer(address newAdmin) external; + + /** + * @dev Completes a `DEFAULT_ADMIN_ROLE` transfer. + * + * Requirements: + * + * - Caller should be the pending default admin. + * - `DEFAULT_ADMIN_ROLE` should be granted to the caller. + * - `DEFAULT_ADMIN_ROLE` should be revoked from the previous holder. + */ + function acceptDefaultAdminTransfer() external; + + /** + * @dev Cancels a `DEFAULT_ADMIN_ROLE` transfer. + * + * Requirements: + * + * - Can be called even after the timer has passed. + * - Can only be called by the current `DEFAULT_ADMIN_ROLE` holder. + */ + function cancelDefaultAdminTransfer() external; +} diff --git a/contracts/access/Ownable.sol b/contracts/access/Ownable.sol index 6d4e866f4..1378ffb43 100644 --- a/contracts/access/Ownable.sol +++ b/contracts/access/Ownable.sol @@ -53,10 +53,10 @@ abstract contract Ownable is Context { /** * @dev Leaves the contract without owner. It will not be possible to call - * `onlyOwner` functions anymore. Can only be called by the current owner. + * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, - * thereby removing any functionality that is only available to the owner. + * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); diff --git a/contracts/access/README.adoc b/contracts/access/README.adoc index 888d0e99e..80ca0020f 100644 --- a/contracts/access/README.adoc +++ b/contracts/access/README.adoc @@ -23,3 +23,5 @@ This directory provides ways to restrict who can access the functions of a contr {{IAccessControlEnumerable}} {{AccessControlEnumerable}} + +{{AccessControlDefaultAdminRules}} diff --git a/contracts/interfaces/README.adoc b/contracts/interfaces/README.adoc index 710c078e8..4525bc9a2 100644 --- a/contracts/interfaces/README.adoc +++ b/contracts/interfaces/README.adoc @@ -64,6 +64,8 @@ are useful to interact with third party contracts that implement them. {{IERC4626}} +{{IERC5313}} + {{IERC5267}} {{IERC5805}} diff --git a/docs/modules/ROOT/pages/access-control.adoc b/docs/modules/ROOT/pages/access-control.adoc index f3ddb6234..56d91e1c1 100644 --- a/docs/modules/ROOT/pages/access-control.adoc +++ b/docs/modules/ROOT/pages/access-control.adoc @@ -131,6 +131,8 @@ Every role has an associated admin role, which grants permission to call the `gr This mechanism can be used to create complex permissioning structures resembling organizational charts, but it also provides an easy way to manage simpler applications. `AccessControl` includes a special role, called `DEFAULT_ADMIN_ROLE`, which acts as the **default admin role for all roles**. An account with this role will be able to manage any other role, unless `_setRoleAdmin` is used to select a new admin role. +Since it is the admin for all roles by default, and in fact it is also its own admin, this role carries significant risk. To mitigate this risk we provide xref:api:access.adoc#AccessControlDefaultAdminRules[`AccessControlDefaultAdminRules`], a recommended extension of `AccessControl` that adds a number of enforced security measures for this role: the admin is restricted to a single account, with a 2-step transfer procedure with a delay in between steps. + Let's take a look at the ERC20 token example, this time taking advantage of the default admin role: [source,solidity] diff --git a/docs/modules/ROOT/pages/extending-contracts.adoc b/docs/modules/ROOT/pages/extending-contracts.adoc index a440f4067..d12ef7585 100644 --- a/docs/modules/ROOT/pages/extending-contracts.adoc +++ b/docs/modules/ROOT/pages/extending-contracts.adoc @@ -66,6 +66,8 @@ contract ModifiedAccessControl is AccessControl { The `super.revokeRole` statement at the end will invoke ``AccessControl``'s original version of `revokeRole`, the same code that would've run if there were no overrides in place. +NOTE: The same rule is implemented and extended in xref:api:access.adoc#AccessControlDefaultAdminRules[`AccessControlDefaultAdminRules`], an extension that also adds enforced security measures for the `DEFAULT_ADMIN_ROLE`. + [[using-hooks]] == Using Hooks diff --git a/test/access/AccessControl.behavior.js b/test/access/AccessControl.behavior.js index a93560983..e04c5a165 100644 --- a/test/access/AccessControl.behavior.js +++ b/test/access/AccessControl.behavior.js @@ -1,5 +1,7 @@ const { expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = require('@openzeppelin/test-helpers/src/constants'); const { expect } = require('chai'); +const { time } = require('@nomicfoundation/hardhat-network-helpers'); const { shouldSupportInterfaces } = require('../utils/introspection/SupportsInterface.behavior'); @@ -210,8 +212,290 @@ function shouldBehaveLikeAccessControlEnumerable(errorPrefix, admin, authorized, }); } +function shouldBehaveLikeAccessControlDefaultAdminRules(errorPrefix, delay, defaultAdmin, newDefaultAdmin, other) { + shouldSupportInterfaces(['AccessControlDefaultAdminRules']); + + it('has a default disabled delayed until', async function () { + expect(await this.accessControl.defaultAdminTransferDelayedUntil()).to.be.bignumber.equal(web3.utils.toBN(0)); + }); + + it('has a default pending default admin', async function () { + expect(await this.accessControl.pendingDefaultAdmin()).to.equal(ZERO_ADDRESS); + }); + + it('has a default current owner set to the initial default admin', async function () { + const owner = await this.accessControl.owner(); + expect(owner).to.equal(defaultAdmin); + expect(await this.accessControl.hasRole(DEFAULT_ADMIN_ROLE, owner)).to.be.true; + }); + + it('should revert if granting default admin role', async function () { + await expectRevert( + this.accessControl.grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin, { from: defaultAdmin }), + `${errorPrefix}: can't directly grant default admin role`, + ); + }); + + it('should revert if revoking default admin role', async function () { + await expectRevert( + this.accessControl.revokeRole(DEFAULT_ADMIN_ROLE, defaultAdmin, { from: defaultAdmin }), + `${errorPrefix}: can't directly revoke default admin role`, + ); + }); + + it("should revert if defaultAdmin's admin is changed", async function () { + await expectRevert( + this.accessControl.$_setRoleAdmin(DEFAULT_ADMIN_ROLE, defaultAdmin), + `${errorPrefix}: can't violate default admin rules`, + ); + }); + + it('should not grant the default admin role twice', async function () { + await expectRevert( + this.accessControl.$_grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin), + `${errorPrefix}: default admin already granted`, + ); + }); + + describe('begins transfer of default admin', function () { + let receipt; + let defaultAdminTransferDelayedUntil; + + beforeEach('begins admin transfer', async function () { + receipt = await this.accessControl.beginDefaultAdminTransfer(newDefaultAdmin, { from: defaultAdmin }); + defaultAdminTransferDelayedUntil = web3.utils.toBN(await time.latest()).add(delay); + }); + + it('should set pending default admin and delayed until', async function () { + expect(await this.accessControl.pendingDefaultAdmin()).to.equal(newDefaultAdmin); + expect(await this.accessControl.defaultAdminTransferDelayedUntil()).to.be.bignumber.equal( + defaultAdminTransferDelayedUntil, + ); + expectEvent(receipt, 'DefaultAdminRoleChangeStarted', { + newDefaultAdmin, + defaultAdminTransferDelayedUntil, + }); + }); + + it('should be able to begin a transfer again before delay pass', async function () { + // Time passes just before delay + await time.setNextBlockTimestamp(defaultAdminTransferDelayedUntil.subn(1)); + + // defaultAdmin changes its mind and begin again to another address + await this.accessControl.beginDefaultAdminTransfer(other, { from: defaultAdmin }); + const newDelayedUntil = web3.utils.toBN(await time.latest()).add(delay); + expect(await this.accessControl.pendingDefaultAdmin()).to.equal(other); + expect(await this.accessControl.defaultAdminTransferDelayedUntil()).to.be.bignumber.equal(newDelayedUntil); + }); + + it('should be able to begin a transfer again after delay pass if not accepted', async function () { + // Time passes after delay without acceptance + await time.setNextBlockTimestamp(defaultAdminTransferDelayedUntil.addn(1)); + + // defaultAdmin changes its mind and begin again to another address + await this.accessControl.beginDefaultAdminTransfer(other, { from: defaultAdmin }); + const newDelayedUntil = web3.utils.toBN(await time.latest()).add(delay); + expect(await this.accessControl.pendingDefaultAdmin()).to.equal(other); + expect(await this.accessControl.defaultAdminTransferDelayedUntil()).to.be.bignumber.equal(newDelayedUntil); + }); + + it('should revert if it is called by non-admin accounts', async function () { + await expectRevert( + this.accessControl.beginDefaultAdminTransfer(newDefaultAdmin, { from: other }), + `${errorPrefix}: account ${other.toLowerCase()} is missing role ${DEFAULT_ADMIN_ROLE}`, + ); + }); + }); + + describe('accepts transfer admin', function () { + let delayPassed; + + beforeEach(async function () { + await this.accessControl.beginDefaultAdminTransfer(newDefaultAdmin, { from: defaultAdmin }); + delayPassed = web3.utils + .toBN(await time.latest()) + .add(delay) + .addn(1); + }); + + describe('caller is pending default admin and delay has passed', function () { + let from; + + beforeEach(async function () { + await time.setNextBlockTimestamp(delayPassed); + from = newDefaultAdmin; + }); + + it('accepts a transfer and changes default admin', async function () { + const receipt = await this.accessControl.acceptDefaultAdminTransfer({ from }); + + // Storage changes + expect(await this.accessControl.hasRole(DEFAULT_ADMIN_ROLE, defaultAdmin)).to.be.false; + expect(await this.accessControl.hasRole(DEFAULT_ADMIN_ROLE, newDefaultAdmin)).to.be.true; + expect(await this.accessControl.owner()).to.equal(newDefaultAdmin); + + // Emit events + expectEvent(receipt, 'RoleRevoked', { + role: DEFAULT_ADMIN_ROLE, + account: defaultAdmin, + }); + expectEvent(receipt, 'RoleGranted', { + role: DEFAULT_ADMIN_ROLE, + account: newDefaultAdmin, + }); + + // Resets pending default admin and delayed until + expect(await this.accessControl.defaultAdminTransferDelayedUntil()).to.be.bignumber.equal(web3.utils.toBN(0)); + expect(await this.accessControl.pendingDefaultAdmin()).to.equal(ZERO_ADDRESS); + }); + }); + + it('should revert if caller is not pending default admin', async function () { + await time.setNextBlockTimestamp(delayPassed); + await expectRevert( + this.accessControl.acceptDefaultAdminTransfer({ from: other }), + `${errorPrefix}: pending admin must accept`, + ); + }); + + describe('delayedUntil not passed', function () { + let delayNotPassed; + + beforeEach(function () { + delayNotPassed = delayPassed.subn(1); + }); + + it('should revert if block.timestamp is equal to delayed until', async function () { + await time.setNextBlockTimestamp(delayNotPassed); + await expectRevert( + this.accessControl.acceptDefaultAdminTransfer({ from: newDefaultAdmin }), + `${errorPrefix}: transfer delay not passed`, + ); + }); + + it('should revert if block.timestamp is less than delayed until', async function () { + await expectRevert( + this.accessControl.acceptDefaultAdminTransfer({ from: newDefaultAdmin }), + `${errorPrefix}: transfer delay not passed`, + ); + }); + }); + }); + + describe('cancel transfer default admin', function () { + let delayPassed; + + beforeEach(async function () { + await this.accessControl.beginDefaultAdminTransfer(newDefaultAdmin, { from: defaultAdmin }); + delayPassed = web3.utils + .toBN(await time.latest()) + .add(delay) + .addn(1); + }); + + it('resets pending default admin and delayed until', async function () { + await this.accessControl.cancelDefaultAdminTransfer({ from: defaultAdmin }); + expect(await this.accessControl.defaultAdminTransferDelayedUntil()).to.be.bignumber.equal(web3.utils.toBN(0)); + expect(await this.accessControl.pendingDefaultAdmin()).to.equal(ZERO_ADDRESS); + + // Advance until passed delay + await time.setNextBlockTimestamp(delayPassed); + + // Previous pending default admin should not be able to accept after cancellation. + await expectRevert( + this.accessControl.acceptDefaultAdminTransfer({ from: newDefaultAdmin }), + `${errorPrefix}: pending admin must accept`, + ); + }); + + it('cancels even after delay has passed', async function () { + await this.accessControl.cancelDefaultAdminTransfer({ from: defaultAdmin }); + await time.setNextBlockTimestamp(delayPassed); + expect(await this.accessControl.defaultAdminTransferDelayedUntil()).to.be.bignumber.equal(web3.utils.toBN(0)); + expect(await this.accessControl.pendingDefaultAdmin()).to.equal(ZERO_ADDRESS); + }); + + it('reverts if called by non default admin accounts', async function () { + await expectRevert( + this.accessControl.cancelDefaultAdminTransfer({ from: other }), + `${errorPrefix}: account ${other.toLowerCase()} is missing role ${DEFAULT_ADMIN_ROLE}`, + ); + }); + }); + + describe('renouncing admin', function () { + let delayPassed; + let from = defaultAdmin; + + beforeEach(async function () { + await this.accessControl.beginDefaultAdminTransfer(ZERO_ADDRESS, { from }); + delayPassed = web3.utils + .toBN(await time.latest()) + .add(delay) + .addn(1); + }); + + it('it renounces role', async function () { + await time.setNextBlockTimestamp(delayPassed); + const receipt = await this.accessControl.renounceRole(DEFAULT_ADMIN_ROLE, from, { from }); + + expect(await this.accessControl.hasRole(DEFAULT_ADMIN_ROLE, defaultAdmin)).to.be.false; + expect(await this.accessControl.hasRole(ZERO_ADDRESS, defaultAdmin)).to.be.false; + expectEvent(receipt, 'RoleRevoked', { + role: DEFAULT_ADMIN_ROLE, + account: from, + }); + expect(await this.accessControl.owner()).to.equal(ZERO_ADDRESS); + }); + + it('allows to recover access using the internal _grantRole', async function () { + await time.setNextBlockTimestamp(delayPassed); + await this.accessControl.renounceRole(DEFAULT_ADMIN_ROLE, from, { from }); + + const grantRoleReceipt = await this.accessControl.$_grantRole(DEFAULT_ADMIN_ROLE, other); + expectEvent(grantRoleReceipt, 'RoleGranted', { + role: DEFAULT_ADMIN_ROLE, + account: other, + }); + }); + + it('reverts if caller is not default admin', async function () { + await time.setNextBlockTimestamp(delayPassed); + await expectRevert( + this.accessControl.renounceRole(DEFAULT_ADMIN_ROLE, other, { from }), + `${errorPrefix}: can only renounce roles for self`, + ); + }); + + describe('delayed until not passed', function () { + let delayNotPassed; + + beforeEach(function () { + delayNotPassed = delayPassed.subn(1); + }); + + it('reverts if block.timestamp is equal to delayed until', async function () { + await time.setNextBlockTimestamp(delayNotPassed); + await expectRevert( + this.accessControl.renounceRole(DEFAULT_ADMIN_ROLE, defaultAdmin, { from }), + `${errorPrefix}: only can renounce in two delayed steps`, + ); + }); + + it('reverts if block.timestamp is less than delayed until', async function () { + await time.setNextBlockTimestamp(delayNotPassed.subn(1)); + await expectRevert( + this.accessControl.renounceRole(DEFAULT_ADMIN_ROLE, defaultAdmin, { from }), + `${errorPrefix}: only can renounce in two delayed steps`, + ); + }); + }); + }); +} + module.exports = { DEFAULT_ADMIN_ROLE, shouldBehaveLikeAccessControl, shouldBehaveLikeAccessControlEnumerable, + shouldBehaveLikeAccessControlDefaultAdminRules, }; diff --git a/test/access/AccessControlDefaultAdminRules.test.js b/test/access/AccessControlDefaultAdminRules.test.js new file mode 100644 index 000000000..2a23d3b6d --- /dev/null +++ b/test/access/AccessControlDefaultAdminRules.test.js @@ -0,0 +1,18 @@ +const { time } = require('@openzeppelin/test-helpers'); +const { + shouldBehaveLikeAccessControl, + shouldBehaveLikeAccessControlDefaultAdminRules, +} = require('./AccessControl.behavior.js'); + +const AccessControlDefaultAdminRules = artifacts.require('$AccessControlDefaultAdminRules'); + +contract('AccessControlDefaultAdminRules', function (accounts) { + const delay = web3.utils.toBN(time.duration.days(10)); + + beforeEach(async function () { + this.accessControl = await AccessControlDefaultAdminRules.new(delay, accounts[0], { from: accounts[0] }); + }); + + shouldBehaveLikeAccessControl('AccessControl', ...accounts); + shouldBehaveLikeAccessControlDefaultAdminRules('AccessControl', delay, ...accounts); +}); diff --git a/test/access/Ownable.test.js b/test/access/Ownable.test.js index dc308f98f..109150874 100644 --- a/test/access/Ownable.test.js +++ b/test/access/Ownable.test.js @@ -37,7 +37,7 @@ contract('Ownable', function (accounts) { }); describe('renounce ownership', function () { - it('loses owner after renouncement', async function () { + it('loses ownership after renouncement', async function () { const receipt = await this.ownable.renounceOwnership({ from: owner }); expectEvent(receipt, 'OwnershipTransferred'); @@ -47,5 +47,13 @@ contract('Ownable', function (accounts) { it('prevents non-owners from renouncement', async function () { await expectRevert(this.ownable.renounceOwnership({ from: other }), 'Ownable: caller is not the owner'); }); + + it('allows to recover access using the internal _transferOwnership', async function () { + await this.ownable.renounceOwnership({ from: owner }); + const receipt = await this.ownable.$_transferOwnership(other); + expectEvent(receipt, 'OwnershipTransferred'); + + expect(await this.ownable.owner()).to.equal(other); + }); }); }); diff --git a/test/access/Ownable2Step.test.js b/test/access/Ownable2Step.test.js index 64d432762..ce043057b 100644 --- a/test/access/Ownable2Step.test.js +++ b/test/access/Ownable2Step.test.js @@ -27,6 +27,16 @@ contract('Ownable2Step', function (accounts) { expect(await this.ownable2Step.pendingOwner()).to.not.equal(accountA); }); + it('guards transfer against invalid user', async function () { + await this.ownable2Step.transferOwnership(accountA, { from: owner }); + await expectRevert( + this.ownable2Step.acceptOwnership({ from: accountB }), + 'Ownable2Step: caller is not the new owner', + ); + }); + }); + + it('renouncing ownership', async function () { it('changes owner after renouncing ownership', async function () { await this.ownable2Step.renounceOwnership({ from: owner }); // If renounceOwnership is removed from parent an alternative is needed ... @@ -46,12 +56,12 @@ contract('Ownable2Step', function (accounts) { ); }); - it('guards transfer against invalid user', async function () { - await this.ownable2Step.transferOwnership(accountA, { from: owner }); - await expectRevert( - this.ownable2Step.acceptOwnership({ from: accountB }), - 'Ownable2Step: caller is not the new owner', - ); + it('allows to recover access using the internal _transferOwnership', async function () { + await this.ownable.renounceOwnership({ from: owner }); + const receipt = await this.ownable.$_transferOwnership(accountA); + expectEvent(receipt, 'OwnershipTransferred'); + + expect(await this.ownable.owner()).to.equal(accountA); }); }); }); diff --git a/test/utils/introspection/SupportsInterface.behavior.js b/test/utils/introspection/SupportsInterface.behavior.js index 02d147884..5ffe242ed 100644 --- a/test/utils/introspection/SupportsInterface.behavior.js +++ b/test/utils/introspection/SupportsInterface.behavior.js @@ -37,6 +37,15 @@ const INTERFACES = { 'renounceRole(bytes32,address)', ], AccessControlEnumerable: ['getRoleMember(bytes32,uint256)', 'getRoleMemberCount(bytes32)'], + AccessControlDefaultAdminRules: [ + 'defaultAdminDelay()', + 'defaultAdmin()', + 'defaultAdminTransferDelayedUntil()', + 'pendingDefaultAdmin()', + 'beginDefaultAdminTransfer(address)', + 'acceptDefaultAdminTransfer()', + 'cancelDefaultAdminTransfer()', + ], Governor: [ 'name()', 'version()', From e1a77ab15f9e311edffe855cf5f5a2f078cdd1ea Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Wed, 1 Mar 2023 19:35:15 +0100 Subject: [PATCH 063/133] Fix an upgrade replay bug in Governor.propose (#4082) --- contracts/governance/Governor.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/governance/Governor.sol b/contracts/governance/Governor.sol index 1483da6d2..12fde79de 100644 --- a/contracts/governance/Governor.sol +++ b/contracts/governance/Governor.sol @@ -276,7 +276,7 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor, IERC721Receive require(targets.length == values.length, "Governor: invalid proposal length"); require(targets.length == calldatas.length, "Governor: invalid proposal length"); require(targets.length > 0, "Governor: empty proposal"); - require(_proposals[proposalId].proposer == address(0), "Governor: proposal already exists"); + require(_proposals[proposalId].voteStart == 0, "Governor: proposal already exists"); uint256 snapshot = currentTimepoint + votingDelay(); uint256 deadline = snapshot + votingPeriod(); From 0ebc6e35295aa276cf5dcc23e871ce087c20d447 Mon Sep 17 00:00:00 2001 From: qedk <1994constant@gmail.com> Date: Thu, 2 Mar 2023 13:40:36 +0400 Subject: [PATCH 064/133] Fix grammar in docs (#4085) --- contracts/governance/Governor.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/governance/Governor.sol b/contracts/governance/Governor.sol index 12fde79de..a2911bf98 100644 --- a/contracts/governance/Governor.sol +++ b/contracts/governance/Governor.sol @@ -21,7 +21,7 @@ import "./IGovernor.sol"; * * - A counting module must implement {quorum}, {_quorumReached}, {_voteSucceeded} and {_countVote} * - A voting module must implement {_getVotes} - * - Additionally, the {votingPeriod} must also be implemented + * - Additionally, {votingPeriod} must also be implemented * * _Available since v4.3._ */ From 8ba26f388f4c1959a071310b4823a7889498e28c Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Thu, 2 Mar 2023 23:41:28 +0100 Subject: [PATCH 065/133] Merge pull request from GHSA-878m-3g6q-594q * Test batch minting of 1 * Fix balance tracking * fix lint * add changeset * rename UNSAFE -> unsafe * fix docs * fix changeset * grammar * add explanation of preserved invariant * add fuzz tests * rename variable * improve property definition * add burn * add test ownership multiple batches * refactor fuzz tests * change ownership test for better probability * typo * reorder comment * update changelog notes * edit changelog * lint * Update CHANGELOG.md --------- Co-authored-by: Francisco Giordano --- .changeset/brave-olives-laugh.md | 5 + CHANGELOG.md | 4 + contracts/token/ERC721/ERC721.sol | 28 ++-- .../ERC721/extensions/ERC721Consecutive.sol | 5 + .../ERC721/extensions/ERC721Consecutive.t.sol | 120 ++++++++++++++++++ .../extensions/ERC721Consecutive.test.js | 3 +- 6 files changed, 149 insertions(+), 16 deletions(-) create mode 100644 .changeset/brave-olives-laugh.md create mode 100644 test/token/ERC721/extensions/ERC721Consecutive.t.sol diff --git a/.changeset/brave-olives-laugh.md b/.changeset/brave-olives-laugh.md new file mode 100644 index 000000000..8cb416323 --- /dev/null +++ b/.changeset/brave-olives-laugh.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': patch +--- + +`ERC721Consecutive`: Fixed a bug when `_mintConsecutive` is used for batches of size 1 that could lead to balance overflow. Refer to the breaking changes section in the changelog for a note on the behavior of `ERC721._beforeTokenTransfer`. diff --git a/CHANGELOG.md b/CHANGELOG.md index e882fd516..1c3a41dd9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ - `ERC777`: The `ERC777` token standard is no longer supported by OpenZeppelin. Our implementation is now deprecated and will be removed in the next major release. The corresponding standard interfaces remain available. ([#4066](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4066)) - `ERC1820Implementer`: The `ERC1820` pseudo-introspection mechanism is no longer supported by OpenZeppelin. Our implementation is now deprecated and will be removed in the next major release. The corresponding standard interfaces remain available. ([#4066](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4066)) +### Breaking changes + +- `ERC721`: The internal function `_beforeTokenTransfer` no longer updates balances, which it previously did when `batchSize` was greater than 1. This change has no consequence unless a custom ERC721 extension is explicitly invoking `_beforeTokenTransfer`. Balance updates in extensions must now be done explicitly using `__unsafe_increaseBalance`, with a name that indicates that there is an invariant that has to be manually verified. + ## 4.8.1 (2023-01-12) - `ERC4626`: Use staticcall instead of call when fetching underlying ERC-20 decimals. ([#3943](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3943)) diff --git a/contracts/token/ERC721/ERC721.sol b/contracts/token/ERC721/ERC721.sol index 6bf620b4f..ea3fffe3f 100644 --- a/contracts/token/ERC721/ERC721.sol +++ b/contracts/token/ERC721/ERC721.sol @@ -434,21 +434,7 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata { * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ - function _beforeTokenTransfer( - address from, - address to, - uint256 /* firstTokenId */, - uint256 batchSize - ) internal virtual { - if (batchSize > 1) { - if (from != address(0)) { - _balances[from] -= batchSize; - } - if (to != address(0)) { - _balances[to] += batchSize; - } - } - } + function _beforeTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize) internal virtual {} /** * @dev Hook that is called after any token transfer. This includes minting and burning. If {ERC721Consecutive} is @@ -465,4 +451,16 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata { * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize) internal virtual {} + + /** + * @dev Unsafe write access to the balances, used by extensions that "mint" tokens using an {ownerOf} override. + * + * WARNING: Anyone calling this MUST ensure that the balances remain consistent with the ownership. The invariant + * being that for any address `a` the value returned by `balanceOf(a)` must be equal to the number of tokens such + * that `ownerOf(tokenId)` is `a`. + */ + // solhint-disable-next-line func-name-mixedcase + function __unsafe_increaseBalance(address account, uint256 amount) internal { + _balances[account] += amount; + } } diff --git a/contracts/token/ERC721/extensions/ERC721Consecutive.sol b/contracts/token/ERC721/extensions/ERC721Consecutive.sol index e6843f1fa..e8610fdf8 100644 --- a/contracts/token/ERC721/extensions/ERC721Consecutive.sol +++ b/contracts/token/ERC721/extensions/ERC721Consecutive.sol @@ -96,6 +96,11 @@ abstract contract ERC721Consecutive is IERC2309, ERC721 { // push an ownership checkpoint & emit event uint96 last = first + batchSize - 1; _sequentialOwnership.push(last, uint160(to)); + + // The invariant required by this function is preserved because the new sequentialOwnership checkpoint + // is attributing ownership of `batchSize` new tokens to account `to`. + __unsafe_increaseBalance(to, batchSize); + emit ConsecutiveTransfer(first, last, address(0), to); // hook after diff --git a/test/token/ERC721/extensions/ERC721Consecutive.t.sol b/test/token/ERC721/extensions/ERC721Consecutive.t.sol new file mode 100644 index 000000000..fc6d3c79f --- /dev/null +++ b/test/token/ERC721/extensions/ERC721Consecutive.t.sol @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../../../contracts/token/ERC721/extensions/ERC721Consecutive.sol"; +import "forge-std/Test.sol"; + +function toSingleton(address account) pure returns (address[] memory) { + address[] memory accounts = new address[](1); + accounts[0] = account; + return accounts; +} + +contract ERC721ConsecutiveTarget is StdUtils, ERC721Consecutive { + uint256 public totalMinted = 0; + + constructor(address[] memory receivers, uint256[] memory batches) ERC721("", "") { + for (uint256 i = 0; i < batches.length; i++) { + address receiver = receivers[i % receivers.length]; + uint96 batchSize = uint96(bound(batches[i], 0, _maxBatchSize())); + _mintConsecutive(receiver, batchSize); + totalMinted += batchSize; + } + } + + function burn(uint256 tokenId) public { + _burn(tokenId); + } +} + +contract ERC721ConsecutiveTest is Test { + function test_balance(address receiver, uint256[] calldata batches) public { + vm.assume(receiver != address(0)); + + ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget(toSingleton(receiver), batches); + + assertEq(token.balanceOf(receiver), token.totalMinted()); + } + + function test_ownership(address receiver, uint256[] calldata batches, uint256[2] calldata unboundedTokenId) public { + vm.assume(receiver != address(0)); + + ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget(toSingleton(receiver), batches); + + if (token.totalMinted() > 0) { + uint256 validTokenId = bound(unboundedTokenId[0], 0, token.totalMinted() - 1); + assertEq(token.ownerOf(validTokenId), receiver); + } + + uint256 invalidTokenId = bound(unboundedTokenId[1], token.totalMinted(), type(uint256).max); + vm.expectRevert(); + token.ownerOf(invalidTokenId); + } + + function test_burn(address receiver, uint256[] calldata batches, uint256 unboundedTokenId) public { + vm.assume(receiver != address(0)); + + ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget(toSingleton(receiver), batches); + + // only test if we minted at least one token + uint256 supply = token.totalMinted(); + vm.assume(supply > 0); + + // burn a token in [0; supply[ + uint256 tokenId = bound(unboundedTokenId, 0, supply - 1); + token.burn(tokenId); + + // balance should have decreased + assertEq(token.balanceOf(receiver), supply - 1); + + // token should be burnt + vm.expectRevert(); + token.ownerOf(tokenId); + } + + function test_transfer( + address[2] calldata accounts, + uint256[2] calldata unboundedBatches, + uint256[2] calldata unboundedTokenId + ) public { + vm.assume(accounts[0] != address(0)); + vm.assume(accounts[1] != address(0)); + vm.assume(accounts[0] != accounts[1]); + + address[] memory receivers = new address[](2); + receivers[0] = accounts[0]; + receivers[1] = accounts[1]; + + // We assume _maxBatchSize is 5000 (the default). This test will break otherwise. + uint256[] memory batches = new uint256[](2); + batches[0] = bound(unboundedBatches[0], 1, 5000); + batches[1] = bound(unboundedBatches[1], 1, 5000); + + ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget(receivers, batches); + + uint256 tokenId0 = bound(unboundedTokenId[0], 0, batches[0] - 1); + uint256 tokenId1 = bound(unboundedTokenId[1], 0, batches[1] - 1) + batches[0]; + + assertEq(token.ownerOf(tokenId0), accounts[0]); + assertEq(token.ownerOf(tokenId1), accounts[1]); + assertEq(token.balanceOf(accounts[0]), batches[0]); + assertEq(token.balanceOf(accounts[1]), batches[1]); + + vm.prank(accounts[0]); + token.transferFrom(accounts[0], accounts[1], tokenId0); + + assertEq(token.ownerOf(tokenId0), accounts[1]); + assertEq(token.ownerOf(tokenId1), accounts[1]); + assertEq(token.balanceOf(accounts[0]), batches[0] - 1); + assertEq(token.balanceOf(accounts[1]), batches[1] + 1); + + vm.prank(accounts[1]); + token.transferFrom(accounts[1], accounts[0], tokenId1); + + assertEq(token.ownerOf(tokenId0), accounts[1]); + assertEq(token.ownerOf(tokenId1), accounts[0]); + assertEq(token.balanceOf(accounts[0]), batches[0]); + assertEq(token.balanceOf(accounts[1]), batches[1]); + } +} diff --git a/test/token/ERC721/extensions/ERC721Consecutive.test.js b/test/token/ERC721/extensions/ERC721Consecutive.test.js index 3d4922846..a92aef480 100644 --- a/test/token/ERC721/extensions/ERC721Consecutive.test.js +++ b/test/token/ERC721/extensions/ERC721Consecutive.test.js @@ -12,7 +12,8 @@ contract('ERC721Consecutive', function (accounts) { const symbol = 'NFT'; const batches = [ { receiver: user1, amount: 0 }, - { receiver: user1, amount: 3 }, + { receiver: user1, amount: 1 }, + { receiver: user1, amount: 2 }, { receiver: user2, amount: 5 }, { receiver: user3, amount: 0 }, { receiver: user1, amount: 7 }, From e58c6d8ff4fd2ddac0320f9b8b7f4fca14f65192 Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Thu, 2 Mar 2023 19:47:41 -0300 Subject: [PATCH 066/133] Fix linter error --- test/token/ERC721/extensions/ERC721Consecutive.t.sol | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/token/ERC721/extensions/ERC721Consecutive.t.sol b/test/token/ERC721/extensions/ERC721Consecutive.t.sol index fc6d3c79f..3cc868929 100644 --- a/test/token/ERC721/extensions/ERC721Consecutive.t.sol +++ b/test/token/ERC721/extensions/ERC721Consecutive.t.sol @@ -2,6 +2,8 @@ pragma solidity ^0.8.0; +// solhint-disable func-name-mixedcase + import "../../../../contracts/token/ERC721/extensions/ERC721Consecutive.sol"; import "forge-std/Test.sol"; From eedca5d873a559140d79cc7ec674d0e28b2b6ebd Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Thu, 2 Mar 2023 21:13:25 -0300 Subject: [PATCH 067/133] Merge release-v4.8 branch --- .changeset/brave-olives-laugh.md | 5 ----- CHANGELOG.md | 4 ++++ contracts/governance/TimelockController.sol | 2 +- contracts/package.json | 2 +- contracts/proxy/utils/Initializable.sol | 2 +- contracts/token/ERC1155/extensions/ERC1155Pausable.sol | 2 +- contracts/token/ERC20/extensions/ERC20Pausable.sol | 2 +- contracts/token/ERC20/extensions/ERC20Votes.sol | 2 +- contracts/token/ERC20/extensions/ERC4626.sol | 2 +- contracts/token/ERC721/ERC721.sol | 2 +- contracts/token/ERC721/extensions/ERC721Consecutive.sol | 2 +- contracts/token/ERC721/extensions/ERC721Pausable.sol | 2 +- contracts/utils/Checkpoints.sol | 2 +- contracts/utils/introspection/ERC165Checker.sol | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 16 files changed, 19 insertions(+), 20 deletions(-) delete mode 100644 .changeset/brave-olives-laugh.md diff --git a/.changeset/brave-olives-laugh.md b/.changeset/brave-olives-laugh.md deleted file mode 100644 index 8cb416323..000000000 --- a/.changeset/brave-olives-laugh.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'openzeppelin-solidity': patch ---- - -`ERC721Consecutive`: Fixed a bug when `_mintConsecutive` is used for batches of size 1 that could lead to balance overflow. Refer to the breaking changes section in the changelog for a note on the behavior of `ERC721._beforeTokenTransfer`. diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c3a41dd9..333b6d4a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ - `ERC777`: The `ERC777` token standard is no longer supported by OpenZeppelin. Our implementation is now deprecated and will be removed in the next major release. The corresponding standard interfaces remain available. ([#4066](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4066)) - `ERC1820Implementer`: The `ERC1820` pseudo-introspection mechanism is no longer supported by OpenZeppelin. Our implementation is now deprecated and will be removed in the next major release. The corresponding standard interfaces remain available. ([#4066](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4066)) +## 4.8.2 (2023-03-02) + +- `ERC721Consecutive`: Fixed a bug when `_mintConsecutive` is used for batches of size 1 that could lead to balance overflow. Refer to the breaking changes section in the changelog for a note on the behavior of `ERC721._beforeTokenTransfer`. + ### Breaking changes - `ERC721`: The internal function `_beforeTokenTransfer` no longer updates balances, which it previously did when `batchSize` was greater than 1. This change has no consequence unless a custom ERC721 extension is explicitly invoking `_beforeTokenTransfer`. Balance updates in extensions must now be done explicitly using `__unsafe_increaseBalance`, with a name that indicates that there is an invariant that has to be manually verified. diff --git a/contracts/governance/TimelockController.sol b/contracts/governance/TimelockController.sol index 615b4c0e3..18ca81e5f 100644 --- a/contracts/governance/TimelockController.sol +++ b/contracts/governance/TimelockController.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v4.8.0) (governance/TimelockController.sol) +// OpenZeppelin Contracts (last updated v4.8.2) (governance/TimelockController.sol) pragma solidity ^0.8.0; diff --git a/contracts/package.json b/contracts/package.json index e3e608341..55e70b179 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -1,7 +1,7 @@ { "name": "@openzeppelin/contracts", "description": "Secure Smart Contract library for Solidity", - "version": "4.8.0", + "version": "4.8.2", "files": [ "**/*.sol", "/build/contracts/*.json", diff --git a/contracts/proxy/utils/Initializable.sol b/contracts/proxy/utils/Initializable.sol index 638dbe353..3c898ec5a 100644 --- a/contracts/proxy/utils/Initializable.sol +++ b/contracts/proxy/utils/Initializable.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/Initializable.sol) +// OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; diff --git a/contracts/token/ERC1155/extensions/ERC1155Pausable.sol b/contracts/token/ERC1155/extensions/ERC1155Pausable.sol index 66ad55e7d..07bb3901a 100644 --- a/contracts/token/ERC1155/extensions/ERC1155Pausable.sol +++ b/contracts/token/ERC1155/extensions/ERC1155Pausable.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/ERC1155Pausable.sol) +// OpenZeppelin Contracts (last updated v4.8.2) (token/ERC1155/extensions/ERC1155Pausable.sol) pragma solidity ^0.8.0; diff --git a/contracts/token/ERC20/extensions/ERC20Pausable.sol b/contracts/token/ERC20/extensions/ERC20Pausable.sol index e011f08c0..36cc30ce4 100644 --- a/contracts/token/ERC20/extensions/ERC20Pausable.sol +++ b/contracts/token/ERC20/extensions/ERC20Pausable.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/ERC20Pausable.sol) +// OpenZeppelin Contracts (last updated v4.8.2) (token/ERC20/extensions/ERC20Pausable.sol) pragma solidity ^0.8.0; diff --git a/contracts/token/ERC20/extensions/ERC20Votes.sol b/contracts/token/ERC20/extensions/ERC20Votes.sol index 273bb8c50..f78938e6d 100644 --- a/contracts/token/ERC20/extensions/ERC20Votes.sol +++ b/contracts/token/ERC20/extensions/ERC20Votes.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/extensions/ERC20Votes.sol) +// OpenZeppelin Contracts (last updated v4.8.1) (token/ERC20/extensions/ERC20Votes.sol) pragma solidity ^0.8.0; diff --git a/contracts/token/ERC20/extensions/ERC4626.sol b/contracts/token/ERC20/extensions/ERC4626.sol index 3846cbbbb..40e9cf2b3 100644 --- a/contracts/token/ERC20/extensions/ERC4626.sol +++ b/contracts/token/ERC20/extensions/ERC4626.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/extensions/ERC4626.sol) +// OpenZeppelin Contracts (last updated v4.8.1) (token/ERC20/extensions/ERC4626.sol) pragma solidity ^0.8.0; diff --git a/contracts/token/ERC721/ERC721.sol b/contracts/token/ERC721/ERC721.sol index ea3fffe3f..428338d90 100644 --- a/contracts/token/ERC721/ERC721.sol +++ b/contracts/token/ERC721/ERC721.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/ERC721.sol) +// OpenZeppelin Contracts (last updated v4.8.2) (token/ERC721/ERC721.sol) pragma solidity ^0.8.0; diff --git a/contracts/token/ERC721/extensions/ERC721Consecutive.sol b/contracts/token/ERC721/extensions/ERC721Consecutive.sol index e8610fdf8..9451c8c59 100644 --- a/contracts/token/ERC721/extensions/ERC721Consecutive.sol +++ b/contracts/token/ERC721/extensions/ERC721Consecutive.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/extensions/ERC721Consecutive.sol) +// OpenZeppelin Contracts (last updated v4.8.2) (token/ERC721/extensions/ERC721Consecutive.sol) pragma solidity ^0.8.0; diff --git a/contracts/token/ERC721/extensions/ERC721Pausable.sol b/contracts/token/ERC721/extensions/ERC721Pausable.sol index cdd729b26..e8eb4b103 100644 --- a/contracts/token/ERC721/extensions/ERC721Pausable.sol +++ b/contracts/token/ERC721/extensions/ERC721Pausable.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/extensions/ERC721Pausable.sol) +// OpenZeppelin Contracts (last updated v4.8.2) (token/ERC721/extensions/ERC721Pausable.sol) pragma solidity ^0.8.0; diff --git a/contracts/utils/Checkpoints.sol b/contracts/utils/Checkpoints.sol index 025b13d0a..7d7905fd1 100644 --- a/contracts/utils/Checkpoints.sol +++ b/contracts/utils/Checkpoints.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v4.8.0) (utils/Checkpoints.sol) +// OpenZeppelin Contracts (last updated v4.8.1) (utils/Checkpoints.sol) // This file was procedurally generated from scripts/generate/templates/Checkpoints.js. pragma solidity ^0.8.0; diff --git a/contracts/utils/introspection/ERC165Checker.sol b/contracts/utils/introspection/ERC165Checker.sol index db6939d83..fd51159cd 100644 --- a/contracts/utils/introspection/ERC165Checker.sol +++ b/contracts/utils/introspection/ERC165Checker.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v4.8.0) (utils/introspection/ERC165Checker.sol) +// OpenZeppelin Contracts (last updated v4.8.2) (utils/introspection/ERC165Checker.sol) pragma solidity ^0.8.0; diff --git a/package-lock.json b/package-lock.json index fc3918807..f3081ffa9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "openzeppelin-solidity", - "version": "4.8.0", + "version": "4.8.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "openzeppelin-solidity", - "version": "4.8.0", + "version": "4.8.2", "license": "MIT", "bin": { "openzeppelin-contracts-migrate-imports": "scripts/migrate-imports.js" diff --git a/package.json b/package.json index f0ee95ab0..282547535 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "openzeppelin-solidity", "description": "Secure Smart Contract library for Solidity", - "version": "4.8.0", + "version": "4.8.2", "files": [ "/contracts/**/*.sol", "/build/contracts/*.json", From 7f028d69593342673492b0a0b1679e2a898cf1cf Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Fri, 3 Mar 2023 22:45:52 +0100 Subject: [PATCH 068/133] Fix empty short string encoding (#4088) Co-authored-by: Francisco --- contracts/utils/ShortStrings.sol | 13 ++++++++++--- test/utils/ShortStrings.test.js | 14 +++++++++++--- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/contracts/utils/ShortStrings.sol b/contracts/utils/ShortStrings.sol index 9f253df82..2f891aaa3 100644 --- a/contracts/utils/ShortStrings.sol +++ b/contracts/utils/ShortStrings.sol @@ -32,7 +32,10 @@ type ShortString is bytes32; * ``` */ library ShortStrings { + bytes32 private constant _FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF; + error StringTooLong(string str); + error InvalidShortString(); /** * @dev Encode a string of at most 31 chars into a `ShortString`. @@ -66,7 +69,11 @@ library ShortStrings { * @dev Return the length of a `ShortString`. */ function length(ShortString sstr) internal pure returns (uint256) { - return uint256(ShortString.unwrap(sstr)) & 0xFF; + uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF; + if (result > 31) { + revert InvalidShortString(); + } + return result; } /** @@ -77,7 +84,7 @@ library ShortStrings { return toShortString(value); } else { StorageSlot.getStringSlot(store).value = value; - return ShortString.wrap(0); + return ShortString.wrap(_FALLBACK_SENTINEL); } } @@ -85,7 +92,7 @@ library ShortStrings { * @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}. */ function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) { - if (length(value) > 0) { + if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) { return toString(value); } else { return store; diff --git a/test/utils/ShortStrings.test.js b/test/utils/ShortStrings.test.js index f41084a7e..27d52a5d7 100644 --- a/test/utils/ShortStrings.test.js +++ b/test/utils/ShortStrings.test.js @@ -3,9 +3,12 @@ const { expectRevertCustomError } = require('../helpers/customError'); const ShortStrings = artifacts.require('$ShortStrings'); +function length(sstr) { + return parseInt(sstr.slice(64), 16); +} + function decode(sstr) { - const length = parseInt(sstr.slice(64), 16); - return web3.utils.toUtf8(sstr).slice(0, length); + return web3.utils.toUtf8(sstr).slice(0, length(sstr)); } contract('ShortStrings', function () { @@ -34,7 +37,12 @@ contract('ShortStrings', function () { const { logs } = await this.mock.$toShortStringWithFallback(str, 0); const { ret0 } = logs.find(({ event }) => event == 'return$toShortStringWithFallback').args; - expect(await this.mock.$toString(ret0)).to.be.equal(str.length < 32 ? str : ''); + const promise = this.mock.$toString(ret0); + if (str.length < 32) { + expect(await promise).to.be.equal(str); + } else { + await expectRevertCustomError(promise, 'InvalidShortString()'); + } const recovered = await this.mock.$toStringWithFallback(ret0, 0); expect(recovered).to.be.equal(str); From de520fe25a75fc9c1e51c4988bc508d8a58da192 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Mon, 6 Mar 2023 21:44:58 +0100 Subject: [PATCH 069/133] Add `byteLengthWithFallback` to ShortStrings (#4089) Co-authored-by: Francisco --- contracts/utils/ShortStrings.sol | 18 ++++++++++++++++-- test/utils/ShortStrings.test.js | 5 ++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/contracts/utils/ShortStrings.sol b/contracts/utils/ShortStrings.sol index 2f891aaa3..450c7985e 100644 --- a/contracts/utils/ShortStrings.sol +++ b/contracts/utils/ShortStrings.sol @@ -54,7 +54,7 @@ library ShortStrings { * @dev Decode a `ShortString` back to a "normal" string. */ function toString(ShortString sstr) internal pure returns (string memory) { - uint256 len = length(sstr); + uint256 len = byteLength(sstr); // using `new string(len)` would work locally but is not memory safe. string memory str = new string(32); /// @solidity memory-safe-assembly @@ -68,7 +68,7 @@ library ShortStrings { /** * @dev Return the length of a `ShortString`. */ - function length(ShortString sstr) internal pure returns (uint256) { + function byteLength(ShortString sstr) internal pure returns (uint256) { uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF; if (result > 31) { revert InvalidShortString(); @@ -98,4 +98,18 @@ library ShortStrings { return store; } } + + /** + * @dev Return the length of a string that was encoded to `ShortString` or written to storage using {setWithFallback}. + * + * WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of + * actual characters as the UTF-8 encoding of a single character can span over multiple bytes. + */ + function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) { + if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) { + return byteLength(value); + } else { + return bytes(store).length; + } + } } diff --git a/test/utils/ShortStrings.test.js b/test/utils/ShortStrings.test.js index 27d52a5d7..f5cd82fbd 100644 --- a/test/utils/ShortStrings.test.js +++ b/test/utils/ShortStrings.test.js @@ -23,7 +23,7 @@ contract('ShortStrings', function () { const encoded = await this.mock.$toShortString(str); expect(decode(encoded)).to.be.equal(str); - const length = await this.mock.$length(encoded); + const length = await this.mock.$byteLength(encoded); expect(length.toNumber()).to.be.equal(str.length); const decoded = await this.mock.$toString(encoded); @@ -44,6 +44,9 @@ contract('ShortStrings', function () { await expectRevertCustomError(promise, 'InvalidShortString()'); } + const length = await this.mock.$byteLengthWithFallback(ret0, 0); + expect(length.toNumber()).to.be.equal(str.length); + const recovered = await this.mock.$toStringWithFallback(ret0, 0); expect(recovered).to.be.equal(str); }); From 4fb6833e325658946c2185862b8e57e32f3683bc Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Mon, 6 Mar 2023 22:31:48 +0100 Subject: [PATCH 070/133] Formal verification using Certora (#4084) Co-authored-by: Francisco Giordano --- .github/workflows/formal-verification.yml | 53 +++ certora/.gitignore | 1 + certora/Makefile | 58 ++- certora/applyHarness.patch | 101 ----- certora/harnesses/AccessControlHarness.sol | 7 + certora/harnesses/ERC20FlashMintHarness.sol | 36 ++ certora/harnesses/ERC20PermitHarness.sol | 18 + certora/harnesses/ERC20VotesHarness.sol | 28 -- .../harnesses/ERC3156FlashBorrowerHarness.sol | 13 + .../harnesses/WizardControlFirstPriority.sol | 150 ------- certora/harnesses/WizardFirstTry.sol | 141 ------ certora/munged/.gitignore | 2 - certora/run.js | 109 +++++ certora/scripts/Governor.sh | 10 - .../GovernorCountingSimple-counting.sh | 10 - certora/scripts/WizardControlFirstPriority.sh | 12 - certora/scripts/WizardFirstTry.sh | 10 - certora/scripts/sanity.sh | 14 - certora/scripts/verifyAll.sh | 39 -- certora/specs.json | 22 + certora/specs/AccessControl.spec | 114 +++++ certora/specs/ERC20.spec | 414 ++++++++++++++++++ certora/specs/ERC20FlashMint.spec | 48 ++ certora/specs/GovernorBase.spec | 333 -------------- certora/specs/GovernorCountingSimple.spec | 221 ---------- certora/specs/RulesInProgress.spec | 139 ------ certora/specs/helpers.spec | 1 + certora/specs/methods/IERC20.spec | 11 + certora/specs/methods/IERC2612.spec | 5 + certora/specs/methods/IERC3156.spec | 5 + certora/specs/sanity.spec | 14 - package-lock.json | 189 ++++---- package.json | 1 + requirements.txt | 1 + 34 files changed, 1011 insertions(+), 1319 deletions(-) create mode 100644 .github/workflows/formal-verification.yml create mode 100644 certora/.gitignore delete mode 100644 certora/applyHarness.patch create mode 100644 certora/harnesses/AccessControlHarness.sol create mode 100644 certora/harnesses/ERC20FlashMintHarness.sol create mode 100644 certora/harnesses/ERC20PermitHarness.sol delete mode 100644 certora/harnesses/ERC20VotesHarness.sol create mode 100644 certora/harnesses/ERC3156FlashBorrowerHarness.sol delete mode 100644 certora/harnesses/WizardControlFirstPriority.sol delete mode 100644 certora/harnesses/WizardFirstTry.sol delete mode 100644 certora/munged/.gitignore create mode 100644 certora/run.js delete mode 100755 certora/scripts/Governor.sh delete mode 100644 certora/scripts/GovernorCountingSimple-counting.sh delete mode 100644 certora/scripts/WizardControlFirstPriority.sh delete mode 100644 certora/scripts/WizardFirstTry.sh delete mode 100644 certora/scripts/sanity.sh delete mode 100644 certora/scripts/verifyAll.sh create mode 100644 certora/specs.json create mode 100644 certora/specs/AccessControl.spec create mode 100644 certora/specs/ERC20.spec create mode 100644 certora/specs/ERC20FlashMint.spec delete mode 100644 certora/specs/GovernorBase.spec delete mode 100644 certora/specs/GovernorCountingSimple.spec delete mode 100644 certora/specs/RulesInProgress.spec create mode 100644 certora/specs/helpers.spec create mode 100644 certora/specs/methods/IERC20.spec create mode 100644 certora/specs/methods/IERC2612.spec create mode 100644 certora/specs/methods/IERC3156.spec delete mode 100644 certora/specs/sanity.spec create mode 100644 requirements.txt diff --git a/.github/workflows/formal-verification.yml b/.github/workflows/formal-verification.yml new file mode 100644 index 000000000..6c9935ad4 --- /dev/null +++ b/.github/workflows/formal-verification.yml @@ -0,0 +1,53 @@ +name: formal verification + +on: + push: + branches: + - master + - release-v* + pull_request: {} + workflow_dispatch: {} + +env: + PIP_VERSION: '3.10' + JAVA_VERSION: '11' + SOLC_VERSION: '0.8.19' + +jobs: + apply-diff: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Apply patches + run: make -C certora apply + + verify: + runs-on: ubuntu-latest + if: github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'formal-verification') + steps: + - uses: actions/checkout@v3 + - name: Set up environment + uses: ./.github/actions/setup + - name: Install python + uses: actions/setup-python@v4 + with: + python-version: ${{ env.PIP_VERSION }} + cache: 'pip' + - name: Install python packages + run: pip install -r requirements.txt + - name: Install java + uses: actions/setup-java@v3 + with: + distribution: temurin + java-version: ${{ env.JAVA_VERSION }} + - name: Install solc + run: | + wget https://github.com/ethereum/solidity/releases/download/v${{ env.SOLC_VERSION }}/solc-static-linux + sudo mv solc-static-linux /usr/local/bin/solc + chmod +x /usr/local/bin/solc + - name: Verify specification + run: | + make -C certora apply + node certora/run.js >> "$GITHUB_STEP_SUMMARY" + env: + CERTORAKEY: ${{ secrets.CERTORAKEY }} diff --git a/certora/.gitignore b/certora/.gitignore new file mode 100644 index 000000000..893adcd31 --- /dev/null +++ b/certora/.gitignore @@ -0,0 +1 @@ +patched diff --git a/certora/Makefile b/certora/Makefile index bbbddbcab..50fd6da08 100644 --- a/certora/Makefile +++ b/certora/Makefile @@ -1,24 +1,54 @@ default: help -PATCH = applyHarness.patch -CONTRACTS_DIR = ../contracts -MUNGED_DIR = munged +SRC := ../contracts +DST := patched +DIFF := diff +SRCS := $(shell find $(SRC) -type f) +DSTS := $(shell find $(DST) -type f) +DIFFS := $(shell find $(DIFF) -type f) +############################################################################### +# Apply all patches in the $DIFF folder to the $DST folder +apply: $(DST) $(patsubst $(DIFF)/%.patch,$(DST)/%,$(subst _,/,$(DIFFS))) + +# Reset the $DST folder +$(DST): FORCE + @rm -rf $@ + @cp -r $(SRC) $@ + +# Update a solidity file in the $DST directory using the corresponding patch +$(DST)/%.sol: FORCE + @echo Applying patch to $@ + @patch -p0 -d $(DST) < $(patsubst $(DST)_%,$(DIFF)/%.patch,$(subst /,_,$@)) + +############################################################################### +# Record all difference between $SRC and $DST in patches +record: $(DIFF) $(patsubst %,$(DIFF)/%.patch,$(subst /,_,$(subst $(SRC)/,,$(SRCS)) $(subst $(DST)/,,$(DSTS)))) + +# Create the $DIFF folder +$(DIFF): FORCE + @rm -rf $@ + @mkdir $@ + +# Create the patch file by comparing the source and the destination +$(DIFF)/%.patch: FORCE + @echo Generating patch $@ + @diff -ruN \ + $(patsubst $(DIFF)/%.patch,$(SRC)/%,$(subst _,/,$@)) \ + $(patsubst $(DIFF)/%.patch,$(DST)/%,$(subst _,/,$@)) \ + | sed 's+$(SRC)/++g' \ + | sed 's+$(DST)/++g' \ + > $@ + @[ -s $@ ] || rm $@ + +############################################################################### help: @echo "usage:" + @echo " make apply: create $(DST) directory by applying the patches to $(SRC)" + @echo " make record: record the patches capturing the differences between $(SRC) and $(DST)" @echo " make clean: remove all generated files (those ignored by git)" - @echo " make $(MUNGED_DIR): create $(MUNGED_DIR) directory by applying the patch file to $(CONTRACTS_DIR)" - @echo " make record: record a new patch file capturing the differences between $(CONTRACTS_DIR) and $(MUNGED_DIR)" - -munged: $(wildcard $(CONTRACTS_DIR)/*.sol) $(PATCH) - rm -rf $@ - cp -r $(CONTRACTS_DIR) $@ - patch -p0 -d $@ < $(PATCH) - -record: - diff -ruN $(CONTRACTS_DIR) $(MUNGED_DIR) | sed 's+../contracts/++g' | sed 's+munged/++g' > $(PATCH) clean: git clean -fdX - touch $(PATCH) +FORCE: ; diff --git a/certora/applyHarness.patch b/certora/applyHarness.patch deleted file mode 100644 index 0fbe9acad..000000000 --- a/certora/applyHarness.patch +++ /dev/null @@ -1,101 +0,0 @@ -diff -ruN .gitignore .gitignore ---- .gitignore 1969-12-31 19:00:00.000000000 -0500 -+++ .gitignore 2021-12-09 14:46:33.923637220 -0500 -@@ -0,0 +1,2 @@ -+* -+!.gitignore -diff -ruN governance/compatibility/GovernorCompatibilityBravo.sol governance/compatibility/GovernorCompatibilityBravo.sol ---- governance/compatibility/GovernorCompatibilityBravo.sol 2021-12-03 15:24:56.523654357 -0500 -+++ governance/compatibility/GovernorCompatibilityBravo.sol 2021-12-09 14:46:33.923637220 -0500 -@@ -245,7 +245,7 @@ - /** - * @dev See {Governor-_quorumReached}. In this module, only forVotes count toward the quorum. - */ -- function _quorumReached(uint256 proposalId) internal view virtual override returns (bool) { -+ function _quorumReached(uint256 proposalId) public view virtual override returns (bool) { // HARNESS: changed to public from internal - ProposalDetails storage details = _proposalDetails[proposalId]; - return quorum(proposalSnapshot(proposalId)) <= details.forVotes; - } -@@ -253,7 +253,7 @@ - /** - * @dev See {Governor-_voteSucceeded}. In this module, the forVotes must be scritly over the againstVotes. - */ -- function _voteSucceeded(uint256 proposalId) internal view virtual override returns (bool) { -+ function _voteSucceeded(uint256 proposalId) public view virtual override returns (bool) { // HARNESS: changed to public from internal - ProposalDetails storage details = _proposalDetails[proposalId]; - return details.forVotes > details.againstVotes; - } -diff -ruN governance/extensions/GovernorCountingSimple.sol governance/extensions/GovernorCountingSimple.sol ---- governance/extensions/GovernorCountingSimple.sol 2021-12-03 15:24:56.523654357 -0500 -+++ governance/extensions/GovernorCountingSimple.sol 2021-12-09 14:46:33.923637220 -0500 -@@ -64,7 +64,7 @@ - /** - * @dev See {Governor-_quorumReached}. - */ -- function _quorumReached(uint256 proposalId) internal view virtual override returns (bool) { -+ function _quorumReached(uint256 proposalId) public view virtual override returns (bool) { - ProposalVote storage proposalvote = _proposalVotes[proposalId]; - - return quorum(proposalSnapshot(proposalId)) <= proposalvote.forVotes + proposalvote.abstainVotes; -@@ -73,7 +73,7 @@ - /** - * @dev See {Governor-_voteSucceeded}. In this module, the forVotes must be strictly over the againstVotes. - */ -- function _voteSucceeded(uint256 proposalId) internal view virtual override returns (bool) { -+ function _voteSucceeded(uint256 proposalId) public view virtual override returns (bool) { - ProposalVote storage proposalvote = _proposalVotes[proposalId]; - - return proposalvote.forVotes > proposalvote.againstVotes; -diff -ruN governance/extensions/GovernorTimelockControl.sol governance/extensions/GovernorTimelockControl.sol ---- governance/extensions/GovernorTimelockControl.sol 2021-12-03 15:24:56.523654357 -0500 -+++ governance/extensions/GovernorTimelockControl.sol 2021-12-09 14:46:33.923637220 -0500 -@@ -111,7 +111,7 @@ - bytes[] memory calldatas, - bytes32 descriptionHash - ) internal virtual override { -- _timelock.executeBatch{value: msg.value}(targets, values, calldatas, 0, descriptionHash); -+ _timelock.executeBatch{value: msg.value}(targets, values, calldatas, 0, descriptionHash); - } - - /** -diff -ruN governance/Governor.sol governance/Governor.sol ---- governance/Governor.sol 2021-12-03 15:24:56.523654357 -0500 -+++ governance/Governor.sol 2021-12-09 14:46:56.411503587 -0500 -@@ -38,8 +38,8 @@ - - string private _name; - -- mapping(uint256 => ProposalCore) private _proposals; -- -+ mapping(uint256 => ProposalCore) public _proposals; -+ - /** - * @dev Restrict access to governor executing address. Some module might override the _executor function to make - * sure this modifier is consistent with the execution model. -@@ -167,12 +167,12 @@ - /** - * @dev Amount of votes already cast passes the threshold limit. - */ -- function _quorumReached(uint256 proposalId) internal view virtual returns (bool); -+ function _quorumReached(uint256 proposalId) public view virtual returns (bool); // HARNESS: changed to public from internal - - /** - * @dev Is the proposal successful or not. - */ -- function _voteSucceeded(uint256 proposalId) internal view virtual returns (bool); -+ function _voteSucceeded(uint256 proposalId) public view virtual returns (bool); // HARNESS: changed to public from internal - - /** - * @dev Register a vote with a given support and voting weight. -diff -ruN token/ERC20/extensions/ERC20Votes.sol token/ERC20/extensions/ERC20Votes.sol ---- token/ERC20/extensions/ERC20Votes.sol 2021-12-03 15:24:56.527654330 -0500 -+++ token/ERC20/extensions/ERC20Votes.sol 2021-12-09 14:46:33.927637196 -0500 -@@ -84,7 +84,7 @@ - * - * - `blockNumber` must have been already mined - */ -- function getPastVotes(address account, uint256 blockNumber) public view returns (uint256) { -+ function getPastVotes(address account, uint256 blockNumber) public view virtual returns (uint256) { - require(blockNumber < block.number, "ERC20Votes: block not yet mined"); - return _checkpointsLookup(_checkpoints[account], blockNumber); - } diff --git a/certora/harnesses/AccessControlHarness.sol b/certora/harnesses/AccessControlHarness.sol new file mode 100644 index 000000000..0cb1e55d4 --- /dev/null +++ b/certora/harnesses/AccessControlHarness.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../patched/access/AccessControl.sol"; + +contract AccessControlHarness is AccessControl {} diff --git a/certora/harnesses/ERC20FlashMintHarness.sol b/certora/harnesses/ERC20FlashMintHarness.sol new file mode 100644 index 000000000..119eb4768 --- /dev/null +++ b/certora/harnesses/ERC20FlashMintHarness.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../patched/token/ERC20/ERC20.sol"; +import "../patched/token/ERC20/extensions/ERC20Permit.sol"; +import "../patched/token/ERC20/extensions/ERC20FlashMint.sol"; + +contract ERC20FlashMintHarness is ERC20, ERC20Permit, ERC20FlashMint { + uint256 someFee; + address someFeeReceiver; + + constructor(string memory name, string memory symbol) ERC20(name, symbol) ERC20Permit(name) {} + + function mint(address account, uint256 amount) external { + _mint(account, amount); + } + + function burn(address account, uint256 amount) external { + _burn(account, amount); + } + + // public accessor + function flashFeeReceiver() public view returns (address) { + return someFeeReceiver; + } + + // internal hook + function _flashFee(address, uint256) internal view override returns (uint256) { + return someFee; + } + + function _flashFeeReceiver() internal view override returns (address) { + return someFeeReceiver; + } +} diff --git a/certora/harnesses/ERC20PermitHarness.sol b/certora/harnesses/ERC20PermitHarness.sol new file mode 100644 index 000000000..cc66358b2 --- /dev/null +++ b/certora/harnesses/ERC20PermitHarness.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../patched/token/ERC20/ERC20.sol"; +import "../patched/token/ERC20/extensions/ERC20Permit.sol"; + +contract ERC20PermitHarness is ERC20, ERC20Permit { + constructor(string memory name, string memory symbol) ERC20(name, symbol) ERC20Permit(name) {} + + function mint(address account, uint256 amount) external { + _mint(account, amount); + } + + function burn(address account, uint256 amount) external { + _burn(account, amount); + } +} diff --git a/certora/harnesses/ERC20VotesHarness.sol b/certora/harnesses/ERC20VotesHarness.sol deleted file mode 100644 index 5067ecfba..000000000 --- a/certora/harnesses/ERC20VotesHarness.sol +++ /dev/null @@ -1,28 +0,0 @@ -import "../munged/token/ERC20/extensions/ERC20Votes.sol"; - -contract ERC20VotesHarness is ERC20Votes { - constructor(string memory name, string memory symbol) ERC20Permit(name) ERC20(name, symbol) {} - - mapping(address => mapping(uint256 => uint256)) public _getPastVotes; - - function _afterTokenTransfer( - address from, - address to, - uint256 amount - ) internal virtual override { - super._afterTokenTransfer(from, to, amount); - _getPastVotes[from][block.number] -= amount; - _getPastVotes[to][block.number] += amount; - } - - /** - * @dev Change delegation for `delegator` to `delegatee`. - * - * Emits events {DelegateChanged} and {DelegateVotesChanged}. - */ - function _delegate(address delegator, address delegatee) internal virtual override{ - super._delegate(delegator, delegatee); - _getPastVotes[delegator][block.number] -= balanceOf(delegator); - _getPastVotes[delegatee][block.number] += balanceOf(delegator); - } -} diff --git a/certora/harnesses/ERC3156FlashBorrowerHarness.sol b/certora/harnesses/ERC3156FlashBorrowerHarness.sol new file mode 100644 index 000000000..0ad29a16e --- /dev/null +++ b/certora/harnesses/ERC3156FlashBorrowerHarness.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT + +import "../patched/interfaces/IERC3156FlashBorrower.sol"; + +pragma solidity ^0.8.0; + +contract ERC3156FlashBorrowerHarness is IERC3156FlashBorrower { + bytes32 somethingToReturn; + + function onFlashLoan(address, address, uint256, uint256, bytes calldata) external view override returns (bytes32) { + return somethingToReturn; + } +} diff --git a/certora/harnesses/WizardControlFirstPriority.sol b/certora/harnesses/WizardControlFirstPriority.sol deleted file mode 100644 index 5ae7fe066..000000000 --- a/certora/harnesses/WizardControlFirstPriority.sol +++ /dev/null @@ -1,150 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.2; - -import "../munged/governance/Governor.sol"; -import "../munged/governance/extensions/GovernorCountingSimple.sol"; -import "../munged/governance/extensions/GovernorVotes.sol"; -import "../munged/governance/extensions/GovernorVotesQuorumFraction.sol"; -import "../munged/governance/extensions/GovernorTimelockControl.sol"; -import "../munged/governance/extensions/GovernorProposalThreshold.sol"; - -/* -Wizard options: -ProposalThreshhold = 10 -ERC20Votes -TimelockController -*/ - -contract WizardControlFirstPriority is Governor, GovernorProposalThreshold, GovernorCountingSimple, GovernorVotes, GovernorVotesQuorumFraction, GovernorTimelockControl { - constructor(ERC20Votes _token, TimelockController _timelock, string memory name, uint256 quorumFraction) - Governor(name) - GovernorVotes(_token) - GovernorVotesQuorumFraction(quorumFraction) - GovernorTimelockControl(_timelock) - {} - - //HARNESS - - function isExecuted(uint256 proposalId) public view returns (bool) { - return _proposals[proposalId].executed; - } - - function isCanceled(uint256 proposalId) public view returns (bool) { - return _proposals[proposalId].canceled; - } - - uint256 _votingDelay; - - uint256 _votingPeriod; - - uint256 _proposalThreshold; - - mapping(uint256 => uint256) public ghost_sum_vote_power_by_id; - - function _castVote( - uint256 proposalId, - address account, - uint8 support, - string memory reason - ) internal override virtual returns (uint256) { - - uint256 deltaWeight = super._castVote(proposalId, account, support, reason); //HARNESS - ghost_sum_vote_power_by_id[proposalId] += deltaWeight; - - return deltaWeight; - } - - function snapshot(uint256 proposalId) public view returns (uint64) { - return _proposals[proposalId].voteStart._deadline; - } - - - function getExecutor() public view returns (address){ - return _executor(); - } - - // original code, harnessed - - function votingDelay() public view override returns (uint256) { // HARNESS: pure -> view - return _votingDelay; // HARNESS: parametric - } - - function votingPeriod() public view override returns (uint256) { // HARNESS: pure -> view - return _votingPeriod; // HARNESS: parametric - } - - function proposalThreshold() public view override returns (uint256) { // HARNESS: pure -> view - return _proposalThreshold; // HARNESS: parametric - } - - // original code, not harnessed - // The following functions are overrides required by Solidity. - - function quorum(uint256 blockNumber) - public - view - override(IGovernor, GovernorVotesQuorumFraction) - returns (uint256) - { - return super.quorum(blockNumber); - } - - function getVotes(address account, uint256 blockNumber) - public - view - override(IGovernor, GovernorVotes) - returns (uint256) - { - return super.getVotes(account, blockNumber); - } - - function state(uint256 proposalId) - public - view - override(Governor, GovernorTimelockControl) - returns (ProposalState) - { - return super.state(proposalId); - } - - function propose(address[] memory targets, uint256[] memory values, bytes[] memory calldatas, string memory description) - public - override(Governor, GovernorProposalThreshold, IGovernor) - returns (uint256) - { - return super.propose(targets, values, calldatas, description); - } - - function _execute(uint256 proposalId, address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash) - internal - override(Governor, GovernorTimelockControl) - { - super._execute(proposalId, targets, values, calldatas, descriptionHash); - } - - function _cancel(address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash) - internal - override(Governor, GovernorTimelockControl) - returns (uint256) - { - return super._cancel(targets, values, calldatas, descriptionHash); - } - - function _executor() - internal - view - override(Governor, GovernorTimelockControl) - returns (address) - { - return super._executor(); - } - - function supportsInterface(bytes4 interfaceId) - public - view - override(Governor, GovernorTimelockControl) - returns (bool) - { - return super.supportsInterface(interfaceId); - } -} diff --git a/certora/harnesses/WizardFirstTry.sol b/certora/harnesses/WizardFirstTry.sol deleted file mode 100644 index 83fece04f..000000000 --- a/certora/harnesses/WizardFirstTry.sol +++ /dev/null @@ -1,141 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.2; - -import "../munged/governance/Governor.sol"; -import "../munged/governance/extensions/GovernorCountingSimple.sol"; -import "../munged/governance/extensions/GovernorVotes.sol"; -import "../munged/governance/extensions/GovernorVotesQuorumFraction.sol"; -import "../munged/governance/extensions/GovernorTimelockCompound.sol"; - -/* -Wizard options: -ERC20Votes -TimelockCompound -*/ - -contract WizardFirstTry is Governor, GovernorCountingSimple, GovernorVotes, GovernorVotesQuorumFraction, GovernorTimelockCompound { - constructor(ERC20Votes _token, ICompoundTimelock _timelock, string memory name, uint256 quorumFraction) - Governor(name) - GovernorVotes(_token) - GovernorVotesQuorumFraction(quorumFraction) - GovernorTimelockCompound(_timelock) - {} - - //HARNESS - - function isExecuted(uint256 proposalId) public view returns (bool) { - return _proposals[proposalId].executed; - } - - function isCanceled(uint256 proposalId) public view returns (bool) { - return _proposals[proposalId].canceled; - } - - function snapshot(uint256 proposalId) public view returns (uint64) { - return _proposals[proposalId].voteStart._deadline; - } - - function getExecutor() public view returns (address){ - return _executor(); - } - - uint256 _votingDelay; - - uint256 _votingPeriod; - - mapping(uint256 => uint256) public ghost_sum_vote_power_by_id; - - function _castVote( - uint256 proposalId, - address account, - uint8 support, - string memory reason - ) internal override virtual returns (uint256) { - - uint256 deltaWeight = super._castVote(proposalId, account, support, reason); //HARNESS - ghost_sum_vote_power_by_id[proposalId] += deltaWeight; - - return deltaWeight; - } - - // original code, harnessed - - function votingDelay() public view override virtual returns (uint256) { // HARNESS: pure -> view - return _votingDelay; // HARNESS: parametric - } - - function votingPeriod() public view override virtual returns (uint256) { // HARNESS: pure -> view - return _votingPeriod; // HARNESS: parametric - } - - // original code, not harnessed - // The following functions are overrides required by Solidity. - - function quorum(uint256 blockNumber) - public - view - override(IGovernor, GovernorVotesQuorumFraction) - returns (uint256) - { - return super.quorum(blockNumber); - } - - function getVotes(address account, uint256 blockNumber) - public - view - override(IGovernor, GovernorVotes) - returns (uint256) - { - return super.getVotes(account, blockNumber); - } - - function state(uint256 proposalId) - public - view - override(Governor, GovernorTimelockCompound) - returns (ProposalState) - { - return super.state(proposalId); - } - - function propose(address[] memory targets, uint256[] memory values, bytes[] memory calldatas, string memory description) - public - override(Governor, IGovernor) - returns (uint256) - { - return super.propose(targets, values, calldatas, description); - } - - function _execute(uint256 proposalId, address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash) - internal - override(Governor, GovernorTimelockCompound) - { - super._execute(proposalId, targets, values, calldatas, descriptionHash); - } - - function _cancel(address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash) - internal - override(Governor, GovernorTimelockCompound) - returns (uint256) - { - return super._cancel(targets, values, calldatas, descriptionHash); - } - - function _executor() - internal - view - override(Governor, GovernorTimelockCompound) - returns (address) - { - return super._executor(); - } - - function supportsInterface(bytes4 interfaceId) - public - view - override(Governor, GovernorTimelockCompound) - returns (bool) - { - return super.supportsInterface(interfaceId); - } -} diff --git a/certora/munged/.gitignore b/certora/munged/.gitignore deleted file mode 100644 index d6b7ef32c..000000000 --- a/certora/munged/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore diff --git a/certora/run.js b/certora/run.js new file mode 100644 index 000000000..1da238d4f --- /dev/null +++ b/certora/run.js @@ -0,0 +1,109 @@ +#!/usr/bin/env node + +// USAGE: +// node certora/run.js [[CONTRACT_NAME:]SPEC_NAME] [OPTIONS...] +// EXAMPLES: +// node certora/run.js AccessControl +// node certora/run.js AccessControlHarness:AccessControl + +const MAX_PARALLEL = 4; + +const specs = require(__dirname + '/specs.json'); + +const proc = require('child_process'); +const { PassThrough } = require('stream'); +const events = require('events'); +const limit = require('p-limit')(MAX_PARALLEL); + +let [, , request = '', ...extraOptions] = process.argv; +if (request.startsWith('-')) { + extraOptions.unshift(request); + request = ''; +} +const [reqSpec, reqContract] = request.split(':').reverse(); + +for (const { spec, contract, files, options = [] } of Object.values(specs)) { + if ((!reqSpec || reqSpec === spec) && (!reqContract || reqContract === contract)) { + limit(runCertora, spec, contract, files, [...options, ...extraOptions]); + } +} + +// Run certora, aggregate the output and print it at the end +async function runCertora(spec, contract, files, options = []) { + const args = [...files, '--verify', `${contract}:certora/specs/${spec}.spec`, ...options]; + const child = proc.spawn('certoraRun', args); + + const stream = new PassThrough(); + const output = collect(stream); + + child.stdout.pipe(stream, { end: false }); + child.stderr.pipe(stream, { end: false }); + + // as soon as we have a jobStatus link, print it + stream.on('data', function logStatusUrl(data) { + const urls = data.toString('utf8').match(/https?:\S*/g); + for (const url of urls ?? []) { + if (url.includes('/jobStatus/')) { + console.error(`[${spec}] ${url}`); + stream.off('data', logStatusUrl); + break; + } + } + }); + + // wait for process end + const [code, signal] = await events.once(child, 'exit'); + + // error + if (code || signal) { + console.error(`[${spec}] Exited with code ${code || signal}`); + process.exitCode = 1; + } + + // get all output + stream.end(); + + // write results in markdown format + writeEntry(spec, contract, code || signal, (await output).match(/https:\S*/)[0]); + + // write all details + console.error(`+ certoraRun ${args.join(' ')}\n` + (await output)); +} + +// Collects stream data into a string +async function collect(stream) { + const buffers = []; + for await (const data of stream) { + const buf = Buffer.isBuffer(data) ? data : Buffer.from(data); + buffers.push(buf); + } + return Buffer.concat(buffers).toString('utf8'); +} + +// Formatting +let hasHeader = false; + +function formatRow(...array) { + return ['', ...array, ''].join(' | '); +} + +function writeHeader() { + console.log(formatRow('spec', 'contract', 'result', 'status', 'output')); + console.log(formatRow('-', '-', '-', '-', '-')); +} + +function writeEntry(spec, contract, success, url) { + if (!hasHeader) { + hasHeader = true; + writeHeader(); + } + console.log( + formatRow( + spec, + contract, + success ? ':x:' : ':heavy_check_mark:', + `[link](${url})`, + `[link](${url.replace('/jobStatus/', '/output/')})`, + ), + ); +} diff --git a/certora/scripts/Governor.sh b/certora/scripts/Governor.sh deleted file mode 100755 index 53ade5060..000000000 --- a/certora/scripts/Governor.sh +++ /dev/null @@ -1,10 +0,0 @@ -make -C certora munged - -certoraRun certora/harnesses/ERC20VotesHarness.sol certora/harnesses/GovernorHarness.sol \ - --verify GovernorHarness:certora/specs/GovernorBase.spec \ - --solc solc8.0 \ - --staging shelly/forSasha \ - --optimistic_loop \ - --settings -copyLoopUnroll=4 \ - --rule voteStartBeforeVoteEnd \ - --msg "$1" diff --git a/certora/scripts/GovernorCountingSimple-counting.sh b/certora/scripts/GovernorCountingSimple-counting.sh deleted file mode 100644 index 9ed8fe34c..000000000 --- a/certora/scripts/GovernorCountingSimple-counting.sh +++ /dev/null @@ -1,10 +0,0 @@ -make -C certora munged - -certoraRun certora/harnesses/ERC20VotesHarness.sol certora/harnesses/GovernorBasicHarness.sol \ - --verify GovernorBasicHarness:certora/specs/GovernorCountingSimple.spec \ - --solc solc8.2 \ - --staging shelly/forSasha \ - --optimistic_loop \ - --settings -copyLoopUnroll=4 \ - --rule hasVotedCorrelation \ - --msg "$1" diff --git a/certora/scripts/WizardControlFirstPriority.sh b/certora/scripts/WizardControlFirstPriority.sh deleted file mode 100644 index b815986ee..000000000 --- a/certora/scripts/WizardControlFirstPriority.sh +++ /dev/null @@ -1,12 +0,0 @@ -make -C certora munged - -certoraRun certora/harnesses/ERC20VotesHarness.sol certora/harnesses/WizardControlFirstPriority.sol \ - --link WizardControlFirstPriority:token=ERC20VotesHarness \ - --verify WizardControlFirstPriority:certora/specs/GovernorBase.spec \ - --solc solc8.2 \ - --disableLocalTypeChecking \ - --staging shelly/forSasha \ - --optimistic_loop \ - --settings -copyLoopUnroll=4 \ - --rule canVoteDuringVotingPeriod \ - --msg "$1" diff --git a/certora/scripts/WizardFirstTry.sh b/certora/scripts/WizardFirstTry.sh deleted file mode 100644 index fd5a32ab4..000000000 --- a/certora/scripts/WizardFirstTry.sh +++ /dev/null @@ -1,10 +0,0 @@ -make -C certora munged - -certoraRun certora/harnesses/ERC20VotesHarness.sol certora/harnesses/WizardFirstTry.sol \ - --verify WizardFirstTry:certora/specs/GovernorBase.spec \ - --solc solc8.2 \ - --staging shelly/forSasha \ - --optimistic_loop \ - --disableLocalTypeChecking \ - --settings -copyLoopUnroll=4 \ - --msg "$1" diff --git a/certora/scripts/sanity.sh b/certora/scripts/sanity.sh deleted file mode 100644 index 1c42bf67b..000000000 --- a/certora/scripts/sanity.sh +++ /dev/null @@ -1,14 +0,0 @@ -make -C certora munged - -for f in certora/harnesses/Wizard*.sol -do - echo "Processing $f" - file="$(basename $f)" - echo ${file%.*} - certoraRun certora/harnesses/$file \ - --verify ${file%.*}:certora/specs/sanity.spec "$@" \ - --solc solc8.2 --staging shelly/forSasha \ - --optimistic_loop \ - --msg "checking sanity on ${file%.*}" - --settings -copyLoopUnroll=4 -done diff --git a/certora/scripts/verifyAll.sh b/certora/scripts/verifyAll.sh deleted file mode 100644 index 9b2f11c8c..000000000 --- a/certora/scripts/verifyAll.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash - -make -C certora munged - -for contract in certora/harnesses/Wizard*.sol; -do - for spec in certora/specs/*.spec; - do - contractFile="$(basename $contract)" - specFile="$(basename $spec)" - if [[ "${specFile%.*}" != "RulesInProgress" ]]; - then - echo "Processing ${contractFile%.*} with $specFile" - if [[ "${contractFile%.*}" = *"WizardControl"* ]]; - then - certoraRun certora/harnesses/ERC20VotesHarness.sol certora/harnesses/$contractFile \ - --link ${contractFile%.*}:token=ERC20VotesHarness \ - --verify ${contractFile%.*}:certora/specs/$specFile "$@" \ - --solc solc8.2 \ - --staging shelly/forSasha \ - --disableLocalTypeChecking \ - --optimistic_loop \ - --settings -copyLoopUnroll=4 \ - --send_only \ - --msg "checking $specFile on ${contractFile%.*}" - else - certoraRun certora/harnesses/ERC20VotesHarness.sol certora/harnesses/$contractFile \ - --verify ${contractFile%.*}:certora/specs/$specFile "$@" \ - --solc solc8.2 \ - --staging shelly/forSasha \ - --disableLocalTypeChecking \ - --optimistic_loop \ - --settings -copyLoopUnroll=4 \ - --send_only \ - --msg "checking $specFile on ${contractFile%.*}" - fi - fi - done -done diff --git a/certora/specs.json b/certora/specs.json new file mode 100644 index 000000000..4d3e1fb90 --- /dev/null +++ b/certora/specs.json @@ -0,0 +1,22 @@ +[ + { + "spec": "AccessControl", + "contract": "AccessControlHarness", + "files": ["certora/harnesses/AccessControlHarness.sol"] + }, + { + "spec": "ERC20", + "contract": "ERC20PermitHarness", + "files": ["certora/harnesses/ERC20PermitHarness.sol"], + "options": ["--optimistic_loop"] + }, + { + "spec": "ERC20FlashMint", + "contract": "ERC20FlashMintHarness", + "files": [ + "certora/harnesses/ERC20FlashMintHarness.sol", + "certora/harnesses/ERC3156FlashBorrowerHarness.sol" + ], + "options": ["--optimistic_loop"] + } +] diff --git a/certora/specs/AccessControl.spec b/certora/specs/AccessControl.spec new file mode 100644 index 000000000..170d56fd4 --- /dev/null +++ b/certora/specs/AccessControl.spec @@ -0,0 +1,114 @@ +import "helpers.spec" + +methods { + hasRole(bytes32, address) returns(bool) envfree + getRoleAdmin(bytes32) returns(bytes32) envfree + grantRole(bytes32, address) + revokeRole(bytes32, address) + renounceRole(bytes32, address) +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Identify entrypoints: only grantRole, revokeRole and renounceRole can alter permissions │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule onlyGrantCanGrant(env e, bytes32 role, address account) { + method f; calldataarg args; + + bool hasRoleBefore = hasRole(role, account); + f(e, args); + bool hasRoleAfter = hasRole(role, account); + + assert ( + !hasRoleBefore && + hasRoleAfter + ) => ( + f.selector == grantRole(bytes32, address).selector + ); + + assert ( + hasRoleBefore && + !hasRoleAfter + ) => ( + f.selector == revokeRole(bytes32, address).selector || + f.selector == renounceRole(bytes32, address).selector + ); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: grantRole only affects the specified user/role combo │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule grantRoleEffect(env e) { + require nonpayable(e); + + bytes32 role1; bytes32 role2; + address account1; address account2; + + bool isCallerAdmin = hasRole(getRoleAdmin(role2), e.msg.sender); + bool hasRoleBefore = hasRole(role1, account1); + + grantRole@withrevert(e, role2, account2); + assert !lastReverted <=> isCallerAdmin; + + bool hasRoleAfter = hasRole(role1, account1); + + assert ( + hasRoleBefore != hasRoleAfter + ) => ( + hasRoleAfter == true && role1 == role2 && account1 == account2 + ); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: revokeRole only affects the specified user/role combo │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule revokeRoleEffect(env e) { + require nonpayable(e); + + bytes32 role1; bytes32 role2; + address account1; address account2; + + bool isCallerAdmin = hasRole(getRoleAdmin(role2), e.msg.sender); + bool hasRoleBefore = hasRole(role1, account1); + + revokeRole@withrevert(e, role2, account2); + assert !lastReverted <=> isCallerAdmin; + + bool hasRoleAfter = hasRole(role1, account1); + + assert ( + hasRoleBefore != hasRoleAfter + ) => ( + hasRoleAfter == false && role1 == role2 && account1 == account2 + ); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: renounceRole only affects the specified user/role combo │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule renounceRoleEffect(env e) { + require nonpayable(e); + + bytes32 role1; bytes32 role2; + address account1; address account2; + + bool hasRoleBefore = hasRole(role1, account1); + + renounceRole@withrevert(e, role2, account2); + assert !lastReverted <=> account2 == e.msg.sender; + + bool hasRoleAfter = hasRole(role1, account1); + + assert ( + hasRoleBefore != hasRoleAfter + ) => ( + hasRoleAfter == false && role1 == role2 && account1 == account2 + ); +} diff --git a/certora/specs/ERC20.spec b/certora/specs/ERC20.spec new file mode 100644 index 000000000..85f95e706 --- /dev/null +++ b/certora/specs/ERC20.spec @@ -0,0 +1,414 @@ +import "helpers.spec" +import "methods/IERC20.spec" +import "methods/IERC2612.spec" + +methods { + // non standard ERC20 functions + increaseAllowance(address,uint256) returns (bool) + decreaseAllowance(address,uint256) returns (bool) + + // exposed for FV + mint(address,uint256) + burn(address,uint256) +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Ghost & hooks: sum of all balances │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +ghost sumOfBalances() returns uint256 { + init_state axiom sumOfBalances() == 0; +} + +hook Sstore _balances[KEY address addr] uint256 newValue (uint256 oldValue) STORAGE { + havoc sumOfBalances assuming sumOfBalances@new() == sumOfBalances@old() + newValue - oldValue; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: totalSupply is the sum of all balances │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant totalSupplyIsSumOfBalances() + totalSupply() == sumOfBalances() + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: balance of address(0) is 0 │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant zeroAddressNoBalance() + balanceOf(0) == 0 + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rules: only mint and burn can change total supply │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule noChangeTotalSupply(env e) { + requireInvariant totalSupplyIsSumOfBalances(); + + method f; + calldataarg args; + + uint256 totalSupplyBefore = totalSupply(); + f(e, args); + uint256 totalSupplyAfter = totalSupply(); + + assert totalSupplyAfter > totalSupplyBefore => f.selector == mint(address,uint256).selector; + assert totalSupplyAfter < totalSupplyBefore => f.selector == burn(address,uint256).selector; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rules: only the token holder or an approved third party can reduce an account's balance │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule onlyAuthorizedCanTransfer(env e) { + requireInvariant totalSupplyIsSumOfBalances(); + + method f; + calldataarg args; + address account; + + uint256 allowanceBefore = allowance(account, e.msg.sender); + uint256 balanceBefore = balanceOf(account); + f(e, args); + uint256 balanceAfter = balanceOf(account); + + assert ( + balanceAfter < balanceBefore + ) => ( + f.selector == burn(address,uint256).selector || + e.msg.sender == account || + balanceBefore - balanceAfter <= allowanceBefore + ); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rules: only the token holder (or a permit) can increase allowance. The spender can decrease it by using it │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule onlyHolderOfSpenderCanChangeAllowance(env e) { + requireInvariant totalSupplyIsSumOfBalances(); + + method f; + calldataarg args; + address holder; + address spender; + + uint256 allowanceBefore = allowance(holder, spender); + f(e, args); + uint256 allowanceAfter = allowance(holder, spender); + + assert ( + allowanceAfter > allowanceBefore + ) => ( + (f.selector == approve(address,uint256).selector && e.msg.sender == holder) || + (f.selector == increaseAllowance(address,uint256).selector && e.msg.sender == holder) || + (f.selector == permit(address,address,uint256,uint256,uint8,bytes32,bytes32).selector) + ); + + assert ( + allowanceAfter < allowanceBefore + ) => ( + (f.selector == transferFrom(address,address,uint256).selector && e.msg.sender == spender) || + (f.selector == approve(address,uint256).selector && e.msg.sender == holder ) || + (f.selector == decreaseAllowance(address,uint256).selector && e.msg.sender == holder ) || + (f.selector == permit(address,address,uint256,uint256,uint8,bytes32,bytes32).selector) + ); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rules: mint behavior and side effects │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule mint(env e) { + requireInvariant totalSupplyIsSumOfBalances(); + require nonpayable(e); + + address to; + address other; + uint256 amount; + + // cache state + uint256 toBalanceBefore = balanceOf(to); + uint256 otherBalanceBefore = balanceOf(other); + uint256 totalSupplyBefore = totalSupply(); + + // run transaction + mint@withrevert(e, to, amount); + + // check outcome + if (lastReverted) { + assert to == 0 || totalSupplyBefore + amount > max_uint256; + } else { + // updates balance and totalSupply + assert balanceOf(to) == toBalanceBefore + amount; + assert totalSupply() == totalSupplyBefore + amount; + + // no other balance is modified + assert balanceOf(other) != otherBalanceBefore => other == to; + } +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rules: burn behavior and side effects │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule burn(env e) { + requireInvariant totalSupplyIsSumOfBalances(); + require nonpayable(e); + + address from; + address other; + uint256 amount; + + // cache state + uint256 fromBalanceBefore = balanceOf(from); + uint256 otherBalanceBefore = balanceOf(other); + uint256 totalSupplyBefore = totalSupply(); + + // run transaction + burn@withrevert(e, from, amount); + + // check outcome + if (lastReverted) { + assert from == 0 || fromBalanceBefore < amount; + } else { + // updates balance and totalSupply + assert balanceOf(from) == fromBalanceBefore - amount; + assert totalSupply() == totalSupplyBefore - amount; + + // no other balance is modified + assert balanceOf(other) != otherBalanceBefore => other == from; + } +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: transfer behavior and side effects │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule transfer(env e) { + requireInvariant totalSupplyIsSumOfBalances(); + require nonpayable(e); + + address holder = e.msg.sender; + address recipient; + address other; + uint256 amount; + + // cache state + uint256 holderBalanceBefore = balanceOf(holder); + uint256 recipientBalanceBefore = balanceOf(recipient); + uint256 otherBalanceBefore = balanceOf(other); + + // run transaction + transfer@withrevert(e, recipient, amount); + + // check outcome + if (lastReverted) { + assert holder == 0 || recipient == 0 || amount > holderBalanceBefore; + } else { + // balances of holder and recipient are updated + assert balanceOf(holder) == holderBalanceBefore - (holder == recipient ? 0 : amount); + assert balanceOf(recipient) == recipientBalanceBefore + (holder == recipient ? 0 : amount); + + // no other balance is modified + assert balanceOf(other) != otherBalanceBefore => (other == holder || other == recipient); + } +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: transferFrom behavior and side effects │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule transferFrom(env e) { + requireInvariant totalSupplyIsSumOfBalances(); + require nonpayable(e); + + address spender = e.msg.sender; + address holder; + address recipient; + address other; + uint256 amount; + + // cache state + uint256 allowanceBefore = allowance(holder, spender); + uint256 holderBalanceBefore = balanceOf(holder); + uint256 recipientBalanceBefore = balanceOf(recipient); + uint256 otherBalanceBefore = balanceOf(other); + + // run transaction + transferFrom@withrevert(e, holder, recipient, amount); + + // check outcome + if (lastReverted) { + assert holder == 0 || recipient == 0 || spender == 0 || amount > holderBalanceBefore || amount > allowanceBefore; + } else { + // allowance is valid & updated + assert allowanceBefore >= amount; + assert allowance(holder, spender) == (allowanceBefore == max_uint256 ? to_uint256(max_uint256) : allowanceBefore - amount); + + // balances of holder and recipient are updated + assert balanceOf(holder) == holderBalanceBefore - (holder == recipient ? 0 : amount); + assert balanceOf(recipient) == recipientBalanceBefore + (holder == recipient ? 0 : amount); + + // no other balance is modified + assert balanceOf(other) != otherBalanceBefore => (other == holder || other == recipient); + } +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: approve behavior and side effects │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule approve(env e) { + require nonpayable(e); + + address holder = e.msg.sender; + address spender; + address otherHolder; + address otherSpender; + uint256 amount; + + // cache state + uint256 otherAllowanceBefore = allowance(otherHolder, otherSpender); + + // run transaction + approve@withrevert(e, spender, amount); + + // check outcome + if (lastReverted) { + assert holder == 0 || spender == 0; + } else { + // allowance is updated + assert allowance(holder, spender) == amount; + + // other allowances are untouched + assert allowance(otherHolder, otherSpender) != otherAllowanceBefore => (otherHolder == holder && otherSpender == spender); + } +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: increaseAllowance behavior and side effects │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule increaseAllowance(env e) { + require nonpayable(e); + + address holder = e.msg.sender; + address spender; + address otherHolder; + address otherSpender; + uint256 amount; + + // cache state + uint256 allowanceBefore = allowance(holder, spender); + uint256 otherAllowanceBefore = allowance(otherHolder, otherSpender); + + // run transaction + increaseAllowance@withrevert(e, spender, amount); + + // check outcome + if (lastReverted) { + assert holder == 0 || spender == 0 || allowanceBefore + amount > max_uint256; + } else { + // allowance is updated + assert allowance(holder, spender) == allowanceBefore + amount; + + // other allowances are untouched + assert allowance(otherHolder, otherSpender) != otherAllowanceBefore => (otherHolder == holder && otherSpender == spender); + } +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: decreaseAllowance behavior and side effects │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule decreaseAllowance(env e) { + require nonpayable(e); + + address holder = e.msg.sender; + address spender; + address otherHolder; + address otherSpender; + uint256 amount; + + // cache state + uint256 allowanceBefore = allowance(holder, spender); + uint256 otherAllowanceBefore = allowance(otherHolder, otherSpender); + + // run transaction + decreaseAllowance@withrevert(e, spender, amount); + + // check outcome + if (lastReverted) { + assert holder == 0 || spender == 0 || allowanceBefore < amount; + } else { + // allowance is updated + assert allowance(holder, spender) == allowanceBefore - amount; + + // other allowances are untouched + assert allowance(otherHolder, otherSpender) != otherAllowanceBefore => (otherHolder == holder && otherSpender == spender); + } +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: permit behavior and side effects │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule permit(env e) { + require nonpayable(e); + + address holder; + address spender; + uint256 amount; + uint256 deadline; + uint8 v; + bytes32 r; + bytes32 s; + + address account1; + address account2; + address account3; + + // cache state + uint256 nonceBefore = nonces(holder); + uint256 otherNonceBefore = nonces(account1); + uint256 otherAllowanceBefore = allowance(account2, account3); + + // sanity: nonce overflow, which possible in theory, is assumed to be impossible in practice + require nonceBefore < max_uint256; + require otherNonceBefore < max_uint256; + + // run transaction + permit@withrevert(e, holder, spender, amount, deadline, v, r, s); + + // check outcome + if (lastReverted) { + // Without formally checking the signature, we can't verify exactly the revert causes + assert true; + } else { + // allowance and nonce are updated + assert allowance(holder, spender) == amount; + assert nonces(holder) == nonceBefore + 1; + + // deadline was respected + assert deadline >= e.block.timestamp; + + // no other allowance or nonce is modified + assert nonces(account1) != otherNonceBefore => account1 == holder; + assert allowance(account2, account3) != otherAllowanceBefore => (account2 == holder && account3 == spender); + } +} diff --git a/certora/specs/ERC20FlashMint.spec b/certora/specs/ERC20FlashMint.spec new file mode 100644 index 000000000..64d97342a --- /dev/null +++ b/certora/specs/ERC20FlashMint.spec @@ -0,0 +1,48 @@ +import "helpers.spec" +import "methods/IERC20.spec" +import "methods/IERC3156.spec" + +methods { + // non standard ERC3156 functions + flashFeeReceiver() returns (address) envfree + + // function summaries below + _mint(address account, uint256 amount) => specMint(account, amount) + _burn(address account, uint256 amount) => specBurn(account, amount) + _transfer(address from, address to, uint256 amount) => specTransfer(from, to, amount) +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Ghost: track mint and burns in the CVL │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +ghost mapping(address => uint256) trackedMintAmount; +ghost mapping(address => uint256) trackedBurnAmount; +ghost mapping(address => mapping(address => uint256)) trackedTransferedAmount; + +function specMint(address account, uint256 amount) returns bool { trackedMintAmount[account] = amount; return true; } +function specBurn(address account, uint256 amount) returns bool { trackedBurnAmount[account] = amount; return true; } +function specTransfer(address from, address to, uint256 amount) returns bool { trackedTransferedAmount[from][to] = amount; return true; } + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: When doing a flashLoan, "amount" is minted and burnt, additionally, the fee is either burnt │ +│ (if the fee recipient is 0) or transferred (if the fee recipient is not 0) │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule checkMintAndBurn(env e) { + address receiver; + address token; + uint256 amount; + bytes data; + + uint256 fees = flashFee(token, amount); + address recipient = flashFeeReceiver(); + + flashLoan(e, receiver, token, amount, data); + + assert trackedMintAmount[receiver] == amount; + assert trackedBurnAmount[receiver] == amount + (recipient == 0 ? fees : 0); + assert (fees > 0 && recipient != 0) => trackedTransferedAmount[receiver][recipient] == fees; +} diff --git a/certora/specs/GovernorBase.spec b/certora/specs/GovernorBase.spec deleted file mode 100644 index de728ddac..000000000 --- a/certora/specs/GovernorBase.spec +++ /dev/null @@ -1,333 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -///////////////////// Governor.sol base definitions ////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -using ERC20VotesHarness as erc20votes - -methods { - proposalSnapshot(uint256) returns uint256 envfree // matches proposalVoteStart - proposalDeadline(uint256) returns uint256 envfree // matches proposalVoteEnd - hashProposal(address[],uint256[],bytes[],bytes32) returns uint256 envfree - isExecuted(uint256) returns bool envfree - isCanceled(uint256) returns bool envfree - execute(address[], uint256[], bytes[], bytes32) returns uint256 - hasVoted(uint256, address) returns bool - castVote(uint256, uint8) returns uint256 - updateQuorumNumerator(uint256) - queue(address[], uint256[], bytes[], bytes32) returns uint256 - - // internal functions made public in harness: - _quorumReached(uint256) returns bool - _voteSucceeded(uint256) returns bool envfree - - // function summarization - proposalThreshold() returns uint256 envfree - - getVotes(address, uint256) returns uint256 => DISPATCHER(true) - - getPastTotalSupply(uint256 t) returns uint256 => PER_CALLEE_CONSTANT - getPastVotes(address a, uint256 t) returns uint256 => PER_CALLEE_CONSTANT - - //scheduleBatch(address[],uint256[],bytes[],bytes32,bytes32,uint256) => DISPATCHER(true) - //executeBatch(address[], uint256[], bytes[], bytes32, bytes32) => DISPATCHER(true) -} - -////////////////////////////////////////////////////////////////////////////// -//////////////////////////////// Definitions ///////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - - -// proposal was created - relation proved in noStartBeforeCreation -definition proposalCreated(uint256 pId) returns bool = proposalSnapshot(pId) > 0; - - -////////////////////////////////////////////////////////////////////////////// -///////////////////////////// Helper Functions /////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -function helperFunctionsWithRevert(uint256 proposalId, method f, env e) { - address[] targets; uint256[] values; bytes[] calldatas; string reason; bytes32 descriptionHash; - uint8 support; uint8 v; bytes32 r; bytes32 s; - if (f.selector == propose(address[], uint256[], bytes[], string).selector) { - uint256 result = propose@withrevert(e, targets, values, calldatas, reason); - require(result == proposalId); - } else if (f.selector == execute(address[], uint256[], bytes[], bytes32).selector) { - uint256 result = execute@withrevert(e, targets, values, calldatas, descriptionHash); - require(result == proposalId); - } else if (f.selector == castVote(uint256, uint8).selector) { - castVote@withrevert(e, proposalId, support); - } else if (f.selector == castVoteWithReason(uint256, uint8, string).selector) { - castVoteWithReason@withrevert(e, proposalId, support, reason); - } else if (f.selector == castVoteBySig(uint256, uint8,uint8, bytes32, bytes32).selector) { - castVoteBySig@withrevert(e, proposalId, support, v, r, s); - } else if (f.selector == queue(address[], uint256[], bytes[], bytes32).selector) { - queue@withrevert(e, targets, values, calldatas, descriptionHash); - } else { - calldataarg args; - f@withrevert(e, args); - } -} - -/* - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////// State Diagram ////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // // - // castVote(s)() // - // ------------- propose() ---------------------- time pass --------------- time passes ----------- // - // | No Proposal | --------> | Before Start (Delay) | --------> | Voting Period | ----------------------> | execute() | // - // ------------- ---------------------- --------------- -> Executed/Canceled ----------- // - // ------------------------------------------------------------|---------------|-------------------------|--------------> // - // t start end timelock // - // // - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -*/ - - -/////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////// Global Valid States ///////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////// - - -/* - * Start and end date are either initialized (non zero) or uninitialized (zero) simultaneously - * This invariant assumes that the block number cannot be 0 at any stage of the contract cycle - * This is very safe assumption as usually the 0 block is genesis block which is uploaded with data - * by the developers and will not be valid to raise proposals (at the current way that block chain is functioning) - */ - // To use env with general preserved block disable type checking [--disableLocalTypeChecking] -invariant startAndEndDatesNonZero(uint256 pId) - proposalSnapshot(pId) != 0 <=> proposalDeadline(pId) != 0 - { preserved with (env e){ - require e.block.number > 0; - }} - - -/* - * If a proposal is canceled it must have a start and an end date - */ - // To use env with general preserved block disable type checking [--disableLocalTypeChecking] -invariant canceledImplyStartAndEndDateNonZero(uint pId) - isCanceled(pId) => proposalSnapshot(pId) != 0 - {preserved with (env e){ - require e.block.number > 0; - }} - - -/* - * If a proposal is executed it must have a start and an end date - */ - // To use env with general preserved block disable type checking [--disableLocalTypeChecking] -invariant executedImplyStartAndEndDateNonZero(uint pId) - isExecuted(pId) => proposalSnapshot(pId) != 0 - { preserved with (env e){ - requireInvariant startAndEndDatesNonZero(pId); - require e.block.number > 0; - }} - - -/* - * A proposal starting block number must be less or equal than the proposal end date - */ -invariant voteStartBeforeVoteEnd(uint256 pId) - // from < to <= because snapshot and deadline can be the same block number if delays are set to 0 - // This is possible before the integration of GovernorSettings.sol to the system. - // After integration of GovernorSettings.sol the invariant expression should be changed from <= to < - (proposalSnapshot(pId) > 0 => proposalSnapshot(pId) <= proposalDeadline(pId)) - // (proposalSnapshot(pId) > 0 => proposalSnapshot(pId) <= proposalDeadline(pId)) - { preserved { - requireInvariant startAndEndDatesNonZero(pId); - }} - - -/* - * A proposal cannot be both executed and canceled simultaneously. - */ -invariant noBothExecutedAndCanceled(uint256 pId) - !isExecuted(pId) || !isCanceled(pId) - - -/* - * A proposal could be executed only if quorum was reached and vote succeeded - */ -rule executionOnlyIfQuoromReachedAndVoteSucceeded(uint256 pId, env e, method f){ - bool isExecutedBefore = isExecuted(pId); - bool quorumReachedBefore = _quorumReached(e, pId); - bool voteSucceededBefore = _voteSucceeded(pId); - - calldataarg args; - f(e, args); - - bool isExecutedAfter = isExecuted(pId); - assert (!isExecutedBefore && isExecutedAfter) => (quorumReachedBefore && voteSucceededBefore), "quorum was changed"; -} - -/////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////// In-State Rules ///////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////// - -//========================================== -//------------- Voting Period -------------- -//========================================== - -/* - * A user cannot vote twice - */ - // Checked for castVote only. all 3 castVote functions call _castVote, so the completeness of the verification is counted on - // the fact that the 3 functions themselves makes no changes, but rather call an internal function to execute. - // That means that we do not check those 3 functions directly, however for castVote & castVoteWithReason it is quite trivial - // to understand why this is ok. For castVoteBySig we basically assume that the signature referendum is correct without checking it. - // We could check each function separately and pass the rule, but that would have uglyfied the code with no concrete - // benefit, as it is evident that nothing is happening in the first 2 functions (calling a view function), and we do not desire to check the signature verification. -rule doubleVoting(uint256 pId, uint8 sup, method f) { - env e; - address user = e.msg.sender; - bool votedCheck = hasVoted(e, pId, user); - - castVote@withrevert(e, pId, sup); - - assert votedCheck => lastReverted, "double voting occurred"; -} - - -/////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////// State Transitions Rules ////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////// - -//=========================================== -//-------- Propose() --> End of Time -------- -//=========================================== - - -/* - * Once a proposal is created, voteStart and voteEnd are immutable - */ -rule immutableFieldsAfterProposalCreation(uint256 pId, method f) { - uint256 _voteStart = proposalSnapshot(pId); - uint256 _voteEnd = proposalDeadline(pId); - - require proposalCreated(pId); // startDate > 0 - - env e; calldataarg arg; - f(e, arg); - - uint256 voteStart_ = proposalSnapshot(pId); - uint256 voteEnd_ = proposalDeadline(pId); - assert _voteStart == voteStart_, "Start date was changed"; - assert _voteEnd == voteEnd_, "End date was changed"; -} - - -/* - * Voting cannot start at a block number prior to proposal’s creation block number - */ -rule noStartBeforeCreation(uint256 pId) { - uint256 previousStart = proposalSnapshot(pId); - // This line makes sure that we see only cases where start date is changed from 0, i.e. creation of proposal - // We proved in immutableFieldsAfterProposalCreation that once dates set for proposal, it cannot be changed - require !proposalCreated(pId); // previousStart == 0; - - env e; calldataarg args; - propose(e, args); - - uint256 newStart = proposalSnapshot(pId); - // if created, start is after current block number (creation block) - assert(newStart != previousStart => newStart >= e.block.number); -} - - -//============================================ -//--- End of Voting Period --> End of Time --- -//============================================ - - -/* - * A proposal can neither be executed nor canceled before it ends - */ - // By induction it cannot be executed nor canceled before it starts, due to voteStartBeforeVoteEnd -rule noExecuteOrCancelBeforeDeadline(uint256 pId, method f){ - require !isExecuted(pId) && !isCanceled(pId); - - env e; calldataarg args; - f(e, args); - - assert e.block.number < proposalDeadline(pId) => (!isExecuted(pId) && !isCanceled(pId)), "executed/cancelled before deadline"; -} - -//////////////////////////////////////////////////////////////////////////////// -////////////////////// Integrity Of Functions (Unit Tests) ///////////////////// -//////////////////////////////////////////////////////////////////////////////// - - -//////////////////////////////////////////////////////////////////////////////// -////////////////////////////// High Level Rules //////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// - - -//////////////////////////////////////////////////////////////////////////////// -///////////////////////////// Not Categorized Yet ////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// - - -/* - * All proposal specific (non-view) functions should revert if proposal is executed - */ - // In this rule we show that if a function is executed, i.e. execute() was called on the proposal ID, - // non of the proposal specific functions can make changes again. In executedOnlyAfterExecuteFunc - // we connected the executed attribute to the execute() function, showing that only execute() can - // change it, and that it will always change it. -rule allFunctionsRevertIfExecuted(method f) filtered { f -> - !f.isView && !f.isFallback - && f.selector != updateTimelock(address).selector - && f.selector != updateQuorumNumerator(uint256).selector - && f.selector != queue(address[],uint256[],bytes[],bytes32).selector - && f.selector != relay(address,uint256,bytes).selector - && f.selector != 0xb9a61961 // __acceptAdmin() -} { - env e; calldataarg args; - uint256 pId; - require(isExecuted(pId)); - requireInvariant noBothExecutedAndCanceled(pId); - requireInvariant executedImplyStartAndEndDateNonZero(pId); - - helperFunctionsWithRevert(pId, f, e); - - assert(lastReverted, "Function was not reverted"); -} - -/* - * All proposal specific (non-view) functions should revert if proposal is canceled - */ -rule allFunctionsRevertIfCanceled(method f) filtered { - f -> !f.isView && !f.isFallback - && f.selector != updateTimelock(address).selector - && f.selector != updateQuorumNumerator(uint256).selector - && f.selector != queue(address[],uint256[],bytes[],bytes32).selector - && f.selector != relay(address,uint256,bytes).selector - && f.selector != 0xb9a61961 // __acceptAdmin() -} { - env e; calldataarg args; - uint256 pId; - require(isCanceled(pId)); - requireInvariant noBothExecutedAndCanceled(pId); - requireInvariant canceledImplyStartAndEndDateNonZero(pId); - - helperFunctionsWithRevert(pId, f, e); - - assert(lastReverted, "Function was not reverted"); -} - -/* - * Proposal can be switched to executed only via execute() function - */ -rule executedOnlyAfterExecuteFunc(address[] targets, uint256[] values, bytes[] calldatas, bytes32 descriptionHash, method f) { - env e; calldataarg args; - uint256 pId; - bool executedBefore = isExecuted(pId); - require(!executedBefore); - - helperFunctionsWithRevert(pId, f, e); - - bool executedAfter = isExecuted(pId); - assert(executedAfter != executedBefore => f.selector == execute(address[], uint256[], bytes[], bytes32).selector, "isExecuted only changes in the execute method"); -} diff --git a/certora/specs/GovernorCountingSimple.spec b/certora/specs/GovernorCountingSimple.spec deleted file mode 100644 index 7af73beb6..000000000 --- a/certora/specs/GovernorCountingSimple.spec +++ /dev/null @@ -1,221 +0,0 @@ -import "GovernorBase.spec" - -using ERC20VotesHarness as erc20votes - -methods { - ghost_sum_vote_power_by_id(uint256) returns uint256 envfree - - quorum(uint256) returns uint256 - proposalVotes(uint256) returns (uint256, uint256, uint256) envfree - - quorumNumerator() returns uint256 - _executor() returns address - - erc20votes._getPastVotes(address, uint256) returns uint256 - - getExecutor() returns address - - timelock() returns address -} - - -////////////////////////////////////////////////////////////////////////////// -///////////////////////////////// GHOSTS ///////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - - -//////////// ghosts to keep track of votes counting //////////// - -/* - * the sum of voting power of those who voted - */ -ghost sum_all_votes_power() returns uint256 { - init_state axiom sum_all_votes_power() == 0; -} - -hook Sstore ghost_sum_vote_power_by_id [KEY uint256 pId] uint256 current_power(uint256 old_power) STORAGE { - havoc sum_all_votes_power assuming sum_all_votes_power@new() == sum_all_votes_power@old() - old_power + current_power; -} - -/* - * sum of all votes casted per proposal - */ -ghost tracked_weight(uint256) returns uint256 { - init_state axiom forall uint256 p. tracked_weight(p) == 0; -} - -/* - * sum of all votes casted - */ -ghost sum_tracked_weight() returns uint256 { - init_state axiom sum_tracked_weight() == 0; -} - -/* - * getter for _proposalVotes.againstVotes - */ -ghost votesAgainst() returns uint256 { - init_state axiom votesAgainst() == 0; -} - -/* - * getter for _proposalVotes.forVotes - */ -ghost votesFor() returns uint256 { - init_state axiom votesFor() == 0; -} - -/* - * getter for _proposalVotes.abstainVotes - */ -ghost votesAbstain() returns uint256 { - init_state axiom votesAbstain() == 0; -} - -hook Sstore _proposalVotes [KEY uint256 pId].againstVotes uint256 votes(uint256 old_votes) STORAGE { - havoc tracked_weight assuming forall uint256 p.(p == pId => tracked_weight@new(p) == tracked_weight@old(p) - old_votes + votes) && - (p != pId => tracked_weight@new(p) == tracked_weight@old(p)); - havoc sum_tracked_weight assuming sum_tracked_weight@new() == sum_tracked_weight@old() - old_votes + votes; - havoc votesAgainst assuming votesAgainst@new() == votesAgainst@old() - old_votes + votes; -} - -hook Sstore _proposalVotes [KEY uint256 pId].forVotes uint256 votes(uint256 old_votes) STORAGE { - havoc tracked_weight assuming forall uint256 p.(p == pId => tracked_weight@new(p) == tracked_weight@old(p) - old_votes + votes) && - (p != pId => tracked_weight@new(p) == tracked_weight@old(p)); - havoc sum_tracked_weight assuming sum_tracked_weight@new() == sum_tracked_weight@old() - old_votes + votes; - havoc votesFor assuming votesFor@new() == votesFor@old() - old_votes + votes; -} - -hook Sstore _proposalVotes [KEY uint256 pId].abstainVotes uint256 votes(uint256 old_votes) STORAGE { - havoc tracked_weight assuming forall uint256 p.(p == pId => tracked_weight@new(p) == tracked_weight@old(p) - old_votes + votes) && - (p != pId => tracked_weight@new(p) == tracked_weight@old(p)); - havoc sum_tracked_weight assuming sum_tracked_weight@new() == sum_tracked_weight@old() - old_votes + votes; - havoc votesAbstain assuming votesAbstain@new() == votesAbstain@old() - old_votes + votes; -} - - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////// INVARIANTS //////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - - -/* - * sum of all votes casted is equal to the sum of voting power of those who voted, per each proposal - */ -invariant SumOfVotesCastEqualSumOfPowerOfVotedPerProposal(uint256 pId) - tracked_weight(pId) == ghost_sum_vote_power_by_id(pId) - - -/* - * sum of all votes casted is equal to the sum of voting power of those who voted - */ -invariant SumOfVotesCastEqualSumOfPowerOfVoted() - sum_tracked_weight() == sum_all_votes_power() - - -/* -* sum of all votes casted is greater or equal to the sum of voting power of those who voted at a specific proposal -*/ -invariant OneIsNotMoreThanAll(uint256 pId) - sum_all_votes_power() >= tracked_weight(pId) - - -////////////////////////////////////////////////////////////////////////////// -///////////////////////////////// RULES ////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - - -/* - * Only sender's voting status can be changed by execution of any cast vote function - */ -// Checked for castVote only. all 3 castVote functions call _castVote, so the completeness of the verification is counted on - // the fact that the 3 functions themselves makes no changes, but rather call an internal function to execute. - // That means that we do not check those 3 functions directly, however for castVote & castVoteWithReason it is quite trivial - // to understand why this is ok. For castVoteBySig we basically assume that the signature referendum is correct without checking it. - // We could check each function separately and pass the rule, but that would have uglyfied the code with no concrete - // benefit, as it is evident that nothing is happening in the first 2 functions (calling a view function), and we do not desire to check the signature verification. -rule noVoteForSomeoneElse(uint256 pId, uint8 sup, method f) { - env e; calldataarg args; - - address voter = e.msg.sender; - address user; - - bool hasVotedBefore_User = hasVoted(e, pId, user); - - castVote@withrevert(e, pId, sup); - require(!lastReverted); - - bool hasVotedAfter_User = hasVoted(e, pId, user); - - assert user != voter => hasVotedBefore_User == hasVotedAfter_User; -} - - -/* -* Total voting tally is monotonically non-decreasing in every operation -*/ -rule votingWeightMonotonicity(method f){ - uint256 votingWeightBefore = sum_tracked_weight(); - - env e; - calldataarg args; - f(e, args); - - uint256 votingWeightAfter = sum_tracked_weight(); - - assert votingWeightBefore <= votingWeightAfter, "Voting weight was decreased somehow"; -} - - -/* -* A change in hasVoted must be correlated with an non-decreasing of the vote supports (nondecrease because user can vote with weight 0) -*/ -rule hasVotedCorrelation(uint256 pId, method f, env e, uint256 bn) { - address acc = e.msg.sender; - - uint256 againstBefore = votesAgainst(); - uint256 forBefore = votesFor(); - uint256 abstainBefore = votesAbstain(); - - bool hasVotedBefore = hasVoted(e, pId, acc); - - helperFunctionsWithRevert(pId, f, e); - require(!lastReverted); - - uint256 againstAfter = votesAgainst(); - uint256 forAfter = votesFor(); - uint256 abstainAfter = votesAbstain(); - - bool hasVotedAfter = hasVoted(e, pId, acc); - - assert (!hasVotedBefore && hasVotedAfter) => againstBefore <= againstAfter || forBefore <= forAfter || abstainBefore <= abstainAfter, "no correlation"; -} - - -/* -* Only privileged users can execute privileged operations, e.g. change _quorumNumerator or _timelock -*/ -rule privilegedOnlyNumerator(method f, uint256 newQuorumNumerator){ - env e; - calldataarg arg; - uint256 quorumNumBefore = quorumNumerator(e); - - f(e, arg); - - uint256 quorumNumAfter = quorumNumerator(e); - address executorCheck = getExecutor(e); - - assert quorumNumBefore != quorumNumAfter => e.msg.sender == executorCheck, "non privileged user changed quorum numerator"; -} - -rule privilegedOnlyTimelock(method f, uint256 newQuorumNumerator){ - env e; - calldataarg arg; - uint256 timelockBefore = timelock(e); - - f(e, arg); - - uint256 timelockAfter = timelock(e); - - assert timelockBefore != timelockAfter => e.msg.sender == timelockBefore, "non privileged user changed timelock"; -} diff --git a/certora/specs/RulesInProgress.spec b/certora/specs/RulesInProgress.spec deleted file mode 100644 index cbad3336e..000000000 --- a/certora/specs/RulesInProgress.spec +++ /dev/null @@ -1,139 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -////////////// THIS SPEC IS A RESERVE FOR NOT IN PROGRESS ////////////// -////////////////////////////////////////////////////////////////////////////// - -import "GovernorBase.spec" - -using ERC20VotesHarness as erc20votes - -methods { - ghost_sum_vote_power_by_id(uint256) returns uint256 envfree - - quorum(uint256) returns uint256 - proposalVotes(uint256) returns (uint256, uint256, uint256) envfree - - quorumNumerator() returns uint256 - _executor() returns address - - erc20votes._getPastVotes(address, uint256) returns uint256 - - getExecutor() returns address - - timelock() returns address -} - - -////////////////////////////////////////////////////////////////////////////// -///////////////////////////////// GHOSTS ///////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - - -//////////// ghosts to keep track of votes counting //////////// - -/* - * the sum of voting power of those who voted - */ -ghost sum_all_votes_power() returns uint256 { - init_state axiom sum_all_votes_power() == 0; -} - -hook Sstore ghost_sum_vote_power_by_id [KEY uint256 pId] uint256 current_power(uint256 old_power) STORAGE { - havoc sum_all_votes_power assuming sum_all_votes_power@new() == sum_all_votes_power@old() - old_power + current_power; -} - -/* - * sum of all votes casted per proposal - */ -ghost tracked_weight(uint256) returns uint256 { - init_state axiom forall uint256 p. tracked_weight(p) == 0; -} - -/* - * sum of all votes casted - */ -ghost sum_tracked_weight() returns uint256 { - init_state axiom sum_tracked_weight() == 0; -} - -/* - * getter for _proposalVotes.againstVotes - */ -ghost votesAgainst() returns uint256 { - init_state axiom votesAgainst() == 0; -} - -/* - * getter for _proposalVotes.forVotes - */ -ghost votesFor() returns uint256 { - init_state axiom votesFor() == 0; -} - -/* - * getter for _proposalVotes.abstainVotes - */ -ghost votesAbstain() returns uint256 { - init_state axiom votesAbstain() == 0; -} - -hook Sstore _proposalVotes [KEY uint256 pId].againstVotes uint256 votes(uint256 old_votes) STORAGE { - havoc tracked_weight assuming forall uint256 p.(p == pId => tracked_weight@new(p) == tracked_weight@old(p) - old_votes + votes) && - (p != pId => tracked_weight@new(p) == tracked_weight@old(p)); - havoc sum_tracked_weight assuming sum_tracked_weight@new() == sum_tracked_weight@old() - old_votes + votes; - havoc votesAgainst assuming votesAgainst@new() == votesAgainst@old() - old_votes + votes; -} - -hook Sstore _proposalVotes [KEY uint256 pId].forVotes uint256 votes(uint256 old_votes) STORAGE { - havoc tracked_weight assuming forall uint256 p.(p == pId => tracked_weight@new(p) == tracked_weight@old(p) - old_votes + votes) && - (p != pId => tracked_weight@new(p) == tracked_weight@old(p)); - havoc sum_tracked_weight assuming sum_tracked_weight@new() == sum_tracked_weight@old() - old_votes + votes; - havoc votesFor assuming votesFor@new() == votesFor@old() - old_votes + votes; -} - -hook Sstore _proposalVotes [KEY uint256 pId].abstainVotes uint256 votes(uint256 old_votes) STORAGE { - havoc tracked_weight assuming forall uint256 p.(p == pId => tracked_weight@new(p) == tracked_weight@old(p) - old_votes + votes) && - (p != pId => tracked_weight@new(p) == tracked_weight@old(p)); - havoc sum_tracked_weight assuming sum_tracked_weight@new() == sum_tracked_weight@old() - old_votes + votes; - havoc votesAbstain assuming votesAbstain@new() == votesAbstain@old() - old_votes + votes; -} - - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////// INVARIANTS //////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - - - -////////////////////////////////////////////////////////////////////////////// -///////////////////////////////// RULES ////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - - -//NOT FINISHED -/* -* the sum of voting power of those who voted is less or equal to the maximum possible votes, per each proposal -*/ -rule possibleTotalVotes(uint256 pId, uint8 sup, env e, method f) { - - // add requireinvariant for all i, j. i = i - 1 && i < j => checkpointlookup[i] < checkpointlookup[j]; - require tracked_weight(pId) <= erc20votes.getPastTotalSupply(e, proposalSnapshot(pId)); - - uint256 againstB; - uint256 forB; - uint256 absatinB; - againstB, forB, absatinB = proposalVotes(pId); - - calldataarg args; - //f(e, args); - - castVote(e, pId, sup); - - uint256 against; - uint256 for; - uint256 absatin; - against, for, absatin = proposalVotes(pId); - - uint256 ps = proposalSnapshot(pId); - - assert tracked_weight(pId) <= erc20votes.getPastTotalSupply(e, proposalSnapshot(pId)), "bla bla bla"; -} \ No newline at end of file diff --git a/certora/specs/helpers.spec b/certora/specs/helpers.spec new file mode 100644 index 000000000..24842d62f --- /dev/null +++ b/certora/specs/helpers.spec @@ -0,0 +1 @@ +definition nonpayable(env e) returns bool = e.msg.value == 0; diff --git a/certora/specs/methods/IERC20.spec b/certora/specs/methods/IERC20.spec new file mode 100644 index 000000000..cfa454e13 --- /dev/null +++ b/certora/specs/methods/IERC20.spec @@ -0,0 +1,11 @@ +methods { + name() returns (string) envfree => DISPATCHER(true) + symbol() returns (string) envfree => DISPATCHER(true) + decimals() returns (uint8) envfree => DISPATCHER(true) + totalSupply() returns (uint256) envfree => DISPATCHER(true) + balanceOf(address) returns (uint256) envfree => DISPATCHER(true) + allowance(address,address) returns (uint256) envfree => DISPATCHER(true) + approve(address,uint256) returns (bool) => DISPATCHER(true) + transfer(address,uint256) returns (bool) => DISPATCHER(true) + transferFrom(address,address,uint256) returns (bool) => DISPATCHER(true) +} diff --git a/certora/specs/methods/IERC2612.spec b/certora/specs/methods/IERC2612.spec new file mode 100644 index 000000000..0c1689da4 --- /dev/null +++ b/certora/specs/methods/IERC2612.spec @@ -0,0 +1,5 @@ +methods { + permit(address,address,uint256,uint256,uint8,bytes32,bytes32) => DISPATCHER(true) + nonces(address) returns (uint256) envfree => DISPATCHER(true) + DOMAIN_SEPARATOR() returns (bytes32) envfree => DISPATCHER(true) +} diff --git a/certora/specs/methods/IERC3156.spec b/certora/specs/methods/IERC3156.spec new file mode 100644 index 000000000..18c10c515 --- /dev/null +++ b/certora/specs/methods/IERC3156.spec @@ -0,0 +1,5 @@ +methods { + maxFlashLoan(address) returns (uint256) envfree => DISPATCHER(true) + flashFee(address,uint256) returns (uint256) envfree => DISPATCHER(true) + flashLoan(address,address,uint256,bytes) returns (bool) => DISPATCHER(true) +} diff --git a/certora/specs/sanity.spec b/certora/specs/sanity.spec deleted file mode 100644 index e08f68845..000000000 --- a/certora/specs/sanity.spec +++ /dev/null @@ -1,14 +0,0 @@ -/* -This rule looks for a non-reverting execution path to each method, including those overridden in the harness. -A method has such an execution path if it violates this rule. -How it works: - - If there is a non-reverting execution path, we reach the false assertion, and the sanity fails. - - If all execution paths are reverting, we never call the assertion, and the method will pass this rule vacuously. -*/ - -rule sanity(method f) { - env e; - calldataarg arg; - f(e, arg); - assert false; -} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index f3081ffa9..b9b491e05 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,6 +39,7 @@ "lodash.zip": "^4.2.0", "merkletreejs": "^0.2.13", "micromatch": "^4.0.2", + "p-limit": "^3.1.0", "prettier": "^2.8.1", "prettier-plugin-solidity": "^1.1.0", "rimraf": "^3.0.2", @@ -215,6 +216,21 @@ "changeset": "bin.js" } }, + "node_modules/@changesets/cli/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@changesets/cli/node_modules/semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -5375,21 +5391,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint/node_modules/p-locate": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", @@ -5835,6 +5836,21 @@ "node": ">= 0.4" } }, + "node_modules/eth-gas-reporter/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/eth-gas-reporter/node_modules/p-locate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", @@ -9516,21 +9532,6 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "node_modules/mocha/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/mocha/node_modules/p-locate": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", @@ -10108,15 +10109,15 @@ } }, "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "dependencies": { - "p-try": "^2.0.0" + "yocto-queue": "^0.1.0" }, "engines": { - "node": ">=6" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -10134,6 +10135,21 @@ "node": ">=8" } }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/p-map": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", @@ -10456,21 +10472,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/preferred-pm/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/preferred-pm/node_modules/p-locate": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", @@ -12942,6 +12943,21 @@ "node": ">= 0.4" } }, + "node_modules/solidity-coverage/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/solidity-coverage/node_modules/p-locate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", @@ -15347,6 +15363,15 @@ "tty-table": "^4.1.5" }, "dependencies": { + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -19264,15 +19289,6 @@ "p-locate": "^5.0.0" } }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, "p-locate": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", @@ -19650,6 +19666,15 @@ "object-keys": "^1.0.11" } }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, "p-locate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", @@ -22564,15 +22589,6 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, "p-locate": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", @@ -23028,12 +23044,12 @@ } }, "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "requires": { - "p-try": "^2.0.0" + "yocto-queue": "^0.1.0" } }, "p-locate": { @@ -23043,6 +23059,17 @@ "dev": true, "requires": { "p-limit": "^2.2.0" + }, + "dependencies": { + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + } } }, "p-map": { @@ -23286,15 +23313,6 @@ "p-locate": "^5.0.0" } }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, "p-locate": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", @@ -25146,6 +25164,15 @@ "object-keys": "^1.0.11" } }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, "p-locate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", diff --git a/package.json b/package.json index 282547535..56798f788 100644 --- a/package.json +++ b/package.json @@ -80,6 +80,7 @@ "lodash.zip": "^4.2.0", "merkletreejs": "^0.2.13", "micromatch": "^4.0.2", + "p-limit": "^3.1.0", "prettier": "^2.8.1", "prettier-plugin-solidity": "^1.1.0", "rimraf": "^3.0.2", diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 000000000..797b3598d --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +certora-cli==3.6.3 From aaad1f4a4ffdba7da789d93a28030e5c411f0181 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Wed, 8 Mar 2023 19:30:07 +0100 Subject: [PATCH 071/133] Add FV specs for Ownable and Ownable2Steps (#4094) Co-authored-by: Santiago Palladino Co-authored-by: Francisco --- certora/harnesses/Ownable2StepHarness.sol | 9 ++ certora/harnesses/OwnableHarness.sol | 9 ++ certora/run.js | 4 +- certora/specs.json | 10 ++ certora/specs/Ownable.spec | 78 ++++++++++++++++ certora/specs/Ownable2Step.spec | 108 ++++++++++++++++++++++ certora/specs/methods/IOwnable.spec | 5 + certora/specs/methods/IOwnable2Step.spec | 7 ++ 8 files changed, 228 insertions(+), 2 deletions(-) create mode 100644 certora/harnesses/Ownable2StepHarness.sol create mode 100644 certora/harnesses/OwnableHarness.sol create mode 100644 certora/specs/Ownable.spec create mode 100644 certora/specs/Ownable2Step.spec create mode 100644 certora/specs/methods/IOwnable.spec create mode 100644 certora/specs/methods/IOwnable2Step.spec diff --git a/certora/harnesses/Ownable2StepHarness.sol b/certora/harnesses/Ownable2StepHarness.sol new file mode 100644 index 000000000..4d30e5041 --- /dev/null +++ b/certora/harnesses/Ownable2StepHarness.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../patched/access/Ownable2Step.sol"; + +contract Ownable2StepHarness is Ownable2Step { + function restricted() external onlyOwner {} +} diff --git a/certora/harnesses/OwnableHarness.sol b/certora/harnesses/OwnableHarness.sol new file mode 100644 index 000000000..93cbb4770 --- /dev/null +++ b/certora/harnesses/OwnableHarness.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../patched/access/Ownable.sol"; + +contract OwnableHarness is Ownable { + function restricted() external onlyOwner {} +} diff --git a/certora/run.js b/certora/run.js index 1da238d4f..161465258 100644 --- a/certora/run.js +++ b/certora/run.js @@ -64,7 +64,7 @@ async function runCertora(spec, contract, files, options = []) { stream.end(); // write results in markdown format - writeEntry(spec, contract, code || signal, (await output).match(/https:\S*/)[0]); + writeEntry(spec, contract, code || signal, (await output).match(/https:\S*/)?.[0]); // write all details console.error(`+ certoraRun ${args.join(' ')}\n` + (await output)); @@ -103,7 +103,7 @@ function writeEntry(spec, contract, success, url) { contract, success ? ':x:' : ':heavy_check_mark:', `[link](${url})`, - `[link](${url.replace('/jobStatus/', '/output/')})`, + `[link](${url?.replace('/jobStatus/', '/output/')})`, ), ); } diff --git a/certora/specs.json b/certora/specs.json index 4d3e1fb90..c22b1ebba 100644 --- a/certora/specs.json +++ b/certora/specs.json @@ -4,6 +4,16 @@ "contract": "AccessControlHarness", "files": ["certora/harnesses/AccessControlHarness.sol"] }, + { + "spec": "Ownable", + "contract": "OwnableHarness", + "files": ["certora/harnesses/OwnableHarness.sol"] + }, + { + "spec": "Ownable2Step", + "contract": "Ownable2StepHarness", + "files": ["certora/harnesses/Ownable2StepHarness.sol"] + }, { "spec": "ERC20", "contract": "ERC20PermitHarness", diff --git a/certora/specs/Ownable.spec b/certora/specs/Ownable.spec new file mode 100644 index 000000000..48bd84d13 --- /dev/null +++ b/certora/specs/Ownable.spec @@ -0,0 +1,78 @@ +import "helpers.spec" +import "methods/IOwnable.spec" + +methods { + restricted() +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: transferOwnership changes ownership │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule transferOwnership(env e) { + require nonpayable(e); + + address newOwner; + address current = owner(); + + transferOwnership@withrevert(e, newOwner); + bool success = !lastReverted; + + assert success <=> (e.msg.sender == current && newOwner != 0), "unauthorized caller or invalid arg"; + assert success => owner() == newOwner, "current owner changed"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: renounceOwnership removes the owner │ + +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule renounceOwnership(env e) { + require nonpayable(e); + + address current = owner(); + + renounceOwnership@withrevert(e); + bool success = !lastReverted; + + assert success <=> e.msg.sender == current, "unauthorized caller"; + assert success => owner() == 0, "owner not cleared"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Access control: only current owner can call restricted functions │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule onlyCurrentOwnerCanCallOnlyOwner(env e) { + require nonpayable(e); + + address current = owner(); + + calldataarg args; + restricted@withrevert(e, args); + + assert !lastReverted <=> e.msg.sender == current, "access control failed"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: ownership can only change in specific ways │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule onlyOwnerOrPendingOwnerCanChangeOwnership(env e, method f) { + address oldCurrent = owner(); + + calldataarg args; + f(e, args); + + address newCurrent = owner(); + + // If owner changes, must be either transferOwnership or renounceOwnership + assert oldCurrent != newCurrent => ( + (e.msg.sender == oldCurrent && newCurrent != 0 && f.selector == transferOwnership(address).selector) || + (e.msg.sender == oldCurrent && newCurrent == 0 && f.selector == renounceOwnership().selector) + ); +} diff --git a/certora/specs/Ownable2Step.spec b/certora/specs/Ownable2Step.spec new file mode 100644 index 000000000..70c520a03 --- /dev/null +++ b/certora/specs/Ownable2Step.spec @@ -0,0 +1,108 @@ +import "helpers.spec" +import "methods/IOwnable2Step.spec" + +methods { + restricted() +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: transferOwnership sets the pending owner │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule transferOwnership(env e) { + require nonpayable(e); + + address newOwner; + address current = owner(); + + transferOwnership@withrevert(e, newOwner); + bool success = !lastReverted; + + assert success <=> e.msg.sender == current, "unauthorized caller"; + assert success => pendingOwner() == newOwner, "pending owner not set"; + assert success => owner() == current, "current owner changed"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: renounceOwnership removes the owner and the pendingOwner │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule renounceOwnership(env e) { + require nonpayable(e); + + address current = owner(); + + renounceOwnership@withrevert(e); + bool success = !lastReverted; + + assert success <=> e.msg.sender == current, "unauthorized caller"; + assert success => pendingOwner() == 0, "pending owner not cleared"; + assert success => owner() == 0, "owner not cleared"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: acceptOwnership changes owner and reset pending owner │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule acceptOwnership(env e) { + + require nonpayable(e); + + address current = owner(); + address pending = pendingOwner(); + + acceptOwnership@withrevert(e); + bool success = !lastReverted; + + assert success <=> e.msg.sender == pending, "unauthorized caller"; + assert success => pendingOwner() == 0, "pending owner not cleared"; + assert success => owner() == pending, "owner not transferred"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Access control: only current owner can call restricted functions │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule onlyCurrentOwnerCanCallOnlyOwner(env e) { + require nonpayable(e); + + address current = owner(); + + calldataarg args; + restricted@withrevert(e, args); + + assert !lastReverted <=> e.msg.sender == current, "access control failed"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: ownership and pending ownership can only change in specific ways │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule ownerOrPendingOwnerChange(env e, method f) { + address oldCurrent = owner(); + address oldPending = pendingOwner(); + + calldataarg args; + f(e, args); + + address newCurrent = owner(); + address newPending = pendingOwner(); + + // If owner changes, must be either acceptOwnership or renounceOwnership + assert oldCurrent != newCurrent => ( + (e.msg.sender == oldPending && newCurrent == oldPending && newPending == 0 && f.selector == acceptOwnership().selector) || + (e.msg.sender == oldCurrent && newCurrent == 0 && newPending == 0 && f.selector == renounceOwnership().selector) + ); + + // If pending changes, must be either acceptance or reset + assert oldPending != newPending => ( + (e.msg.sender == oldCurrent && newCurrent == oldCurrent && f.selector == transferOwnership(address).selector) || + (e.msg.sender == oldPending && newCurrent == oldPending && newPending == 0 && f.selector == acceptOwnership().selector) || + (e.msg.sender == oldCurrent && newCurrent == 0 && newPending == 0 && f.selector == renounceOwnership().selector) + ); +} diff --git a/certora/specs/methods/IOwnable.spec b/certora/specs/methods/IOwnable.spec new file mode 100644 index 000000000..cfa15f95f --- /dev/null +++ b/certora/specs/methods/IOwnable.spec @@ -0,0 +1,5 @@ +methods { + owner() returns (address) envfree + transferOwnership(address) + renounceOwnership() +} diff --git a/certora/specs/methods/IOwnable2Step.spec b/certora/specs/methods/IOwnable2Step.spec new file mode 100644 index 000000000..c8e671d27 --- /dev/null +++ b/certora/specs/methods/IOwnable2Step.spec @@ -0,0 +1,7 @@ +methods { + owner() returns (address) envfree + pendingOwner() returns (address) envfree + transferOwnership(address) + acceptOwnership() + renounceOwnership() +} From a55013e742d0673394192e3df36c58778f8d8a59 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Wed, 8 Mar 2023 19:31:46 +0100 Subject: [PATCH 072/133] Add effect checks on the accesscontrol specs (#4099) --- certora/specs/AccessControl.spec | 85 +++++++++++++++++++------------- 1 file changed, 50 insertions(+), 35 deletions(-) diff --git a/certora/specs/AccessControl.spec b/certora/specs/AccessControl.spec index 170d56fd4..8e8f6ac9d 100644 --- a/certora/specs/AccessControl.spec +++ b/certora/specs/AccessControl.spec @@ -44,22 +44,27 @@ rule onlyGrantCanGrant(env e, bytes32 role, address account) { rule grantRoleEffect(env e) { require nonpayable(e); - bytes32 role1; bytes32 role2; - address account1; address account2; + bytes32 role; + bytes32 otherRole; + address account; + address otherAccount; - bool isCallerAdmin = hasRole(getRoleAdmin(role2), e.msg.sender); - bool hasRoleBefore = hasRole(role1, account1); + bool isCallerAdmin = hasRole(getRoleAdmin(role), e.msg.sender); + bool hasOtherRoleBefore = hasRole(otherRole, otherAccount); - grantRole@withrevert(e, role2, account2); - assert !lastReverted <=> isCallerAdmin; + grantRole@withrevert(e, role, account); + bool success = !lastReverted; - bool hasRoleAfter = hasRole(role1, account1); + bool hasOtherRoleAfter = hasRole(otherRole, otherAccount); - assert ( - hasRoleBefore != hasRoleAfter - ) => ( - hasRoleAfter == true && role1 == role2 && account1 == account2 - ); + // liveness + assert success <=> isCallerAdmin; + + // effect + assert success => hasRole(role, account); + + // no side effect + assert hasOtherRoleBefore != hasOtherRoleAfter => (role == otherRole && account == otherAccount); } /* @@ -70,22 +75,27 @@ rule grantRoleEffect(env e) { rule revokeRoleEffect(env e) { require nonpayable(e); - bytes32 role1; bytes32 role2; - address account1; address account2; + bytes32 role; + bytes32 otherRole; + address account; + address otherAccount; - bool isCallerAdmin = hasRole(getRoleAdmin(role2), e.msg.sender); - bool hasRoleBefore = hasRole(role1, account1); + bool isCallerAdmin = hasRole(getRoleAdmin(role), e.msg.sender); + bool hasOtherRoleBefore = hasRole(otherRole, otherAccount); - revokeRole@withrevert(e, role2, account2); - assert !lastReverted <=> isCallerAdmin; + revokeRole@withrevert(e, role, account); + bool success = !lastReverted; - bool hasRoleAfter = hasRole(role1, account1); + bool hasOtherRoleAfter = hasRole(otherRole, otherAccount); - assert ( - hasRoleBefore != hasRoleAfter - ) => ( - hasRoleAfter == false && role1 == role2 && account1 == account2 - ); + // liveness + assert success <=> isCallerAdmin; + + // effect + assert success => !hasRole(role, account); + + // no side effect + assert hasOtherRoleBefore != hasOtherRoleAfter => (role == otherRole && account == otherAccount); } /* @@ -96,19 +106,24 @@ rule revokeRoleEffect(env e) { rule renounceRoleEffect(env e) { require nonpayable(e); - bytes32 role1; bytes32 role2; - address account1; address account2; + bytes32 role; + bytes32 otherRole; + address account; + address otherAccount; - bool hasRoleBefore = hasRole(role1, account1); + bool hasOtherRoleBefore = hasRole(otherRole, otherAccount); - renounceRole@withrevert(e, role2, account2); - assert !lastReverted <=> account2 == e.msg.sender; + renounceRole@withrevert(e, role, account); + bool success = !lastReverted; - bool hasRoleAfter = hasRole(role1, account1); + bool hasOtherRoleAfter = hasRole(otherRole, otherAccount); - assert ( - hasRoleBefore != hasRoleAfter - ) => ( - hasRoleAfter == false && role1 == role2 && account1 == account2 - ); + // liveness + assert success <=> account == e.msg.sender; + + // effect + assert success => !hasRole(role, account); + + // no side effect + assert hasOtherRoleBefore != hasOtherRoleAfter => (role == otherRole && account == otherAccount); } From b952a82d29661995d75c476501f977b716860e58 Mon Sep 17 00:00:00 2001 From: Francisco Date: Wed, 8 Mar 2023 18:16:37 -0300 Subject: [PATCH 073/133] Throw error when requested specs are not found (#4101) --- certora/run.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/certora/run.js b/certora/run.js index 161465258..172309e19 100644 --- a/certora/run.js +++ b/certora/run.js @@ -8,7 +8,7 @@ const MAX_PARALLEL = 4; -const specs = require(__dirname + '/specs.json'); +let specs = require(__dirname + '/specs.json'); const proc = require('child_process'); const { PassThrough } = require('stream'); @@ -20,12 +20,18 @@ if (request.startsWith('-')) { extraOptions.unshift(request); request = ''; } -const [reqSpec, reqContract] = request.split(':').reverse(); + +if (request) { + const [reqSpec, reqContract] = request.split(':').reverse(); + specs = Object.values(specs).filter(s => reqSpec === s.spec && (!reqContract || reqContract === s.contract)); + if (specs.length === 0) { + console.error(`Error: Requested spec '${request}' not found in specs.json`); + process.exit(1); + } +} for (const { spec, contract, files, options = [] } of Object.values(specs)) { - if ((!reqSpec || reqSpec === spec) && (!reqContract || reqContract === contract)) { - limit(runCertora, spec, contract, files, [...options, ...extraOptions]); - } + limit(runCertora, spec, contract, files, [...options, ...extraOptions]); } // Run certora, aggregate the output and print it at the end From 5f7f660c6e247cf0e91d87c6d64635908997f738 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Wed, 8 Mar 2023 22:17:35 +0100 Subject: [PATCH 074/133] Add FV specs for Initializable (#4095) Co-authored-by: Francisco --- certora/harnesses/InitializableHarness.sol | 23 +++ certora/specs.json | 5 + certora/specs/Initializable.spec | 165 +++++++++++++++++++++ 3 files changed, 193 insertions(+) create mode 100644 certora/harnesses/InitializableHarness.sol create mode 100644 certora/specs/Initializable.spec diff --git a/certora/harnesses/InitializableHarness.sol b/certora/harnesses/InitializableHarness.sol new file mode 100644 index 000000000..19437e0fc --- /dev/null +++ b/certora/harnesses/InitializableHarness.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.2; + +import "../patched/proxy/utils/Initializable.sol"; + +contract InitializableHarness is Initializable { + function initialize() public initializer {} + function reinitialize(uint8 n) public reinitializer(n) {} + function disable() public { _disableInitializers(); } + + function nested_init_init() public initializer { initialize(); } + function nested_init_reinit(uint8 m) public initializer { reinitialize(m); } + function nested_reinit_init(uint8 n) public reinitializer(n) { initialize(); } + function nested_reinit_reinit(uint8 n, uint8 m) public reinitializer(n) { reinitialize(m); } + + function version() public view returns (uint8) { + return _getInitializedVersion(); + } + + function initializing() public view returns (bool) { + return _isInitializing(); + } +} diff --git a/certora/specs.json b/certora/specs.json index c22b1ebba..8e4fe21f4 100644 --- a/certora/specs.json +++ b/certora/specs.json @@ -28,5 +28,10 @@ "certora/harnesses/ERC3156FlashBorrowerHarness.sol" ], "options": ["--optimistic_loop"] + }, + { + "spec": "Initializable", + "contract": "InitializableHarness", + "files": ["certora/harnesses/InitializableHarness.sol"] } ] diff --git a/certora/specs/Initializable.spec b/certora/specs/Initializable.spec new file mode 100644 index 000000000..1ba8d54e8 --- /dev/null +++ b/certora/specs/Initializable.spec @@ -0,0 +1,165 @@ +import "helpers.spec" + +methods { + // initialize, reinitialize, disable + initialize() envfree + reinitialize(uint8) envfree + disable() envfree + + nested_init_init() envfree + nested_init_reinit(uint8) envfree + nested_reinit_init(uint8) envfree + nested_reinit_reinit(uint8,uint8) envfree + + // view + version() returns uint8 envfree + initializing() returns bool envfree +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Definitions │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +definition isUninitialized() returns bool = version() == 0; +definition isInitialized() returns bool = version() > 0; +definition isDisabled() returns bool = version() == 255; + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: A contract must only ever be in an initializing state while in the middle of a transaction execution. │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant notInitializing() + !initializing() + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: The version cannot decrease & disable state is irrevocable. │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule increasingVersion(env e) { + uint8 versionBefore = version(); + bool disabledBefore = isDisabled(); + + method f; calldataarg args; + f(e, args); + + assert versionBefore <= version(), "_initialized must only increase"; + assert disabledBefore => isDisabled(), "a disabled initializer must stay disabled"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: Cannot initialize a contract that is already initialized. │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule cannotInitializeTwice() { + require isInitialized(); + + initialize@withrevert(); + + assert lastReverted, "contract must only be initialized once"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: Cannot initialize once disabled. │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule cannotInitializeOnceDisabled() { + require isDisabled(); + + initialize@withrevert(); + + assert lastReverted, "contract is disabled"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: Cannot reinitialize once disabled. │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule cannotReinitializeOnceDisabled() { + require isDisabled(); + + uint8 n; + reinitialize@withrevert(n); + + assert lastReverted, "contract is disabled"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: Cannot nest initializers (after construction). │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule cannotNestInitializers_init_init() { + nested_init_init@withrevert(); + assert lastReverted, "nested initializers"; +} + +rule cannotNestInitializers_init_reinit(uint8 m) { + nested_init_reinit@withrevert(m); + assert lastReverted, "nested initializers"; +} + +rule cannotNestInitializers_reinit_init(uint8 n) { + nested_reinit_init@withrevert(n); + assert lastReverted, "nested initializers"; +} + +rule cannotNestInitializers_reinit_reinit(uint8 n, uint8 m) { + nested_reinit_reinit@withrevert(n, m); + assert lastReverted, "nested initializers"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: Initialize correctly sets the version. │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule initializeEffects() { + requireInvariant notInitializing(); + + bool isUninitializedBefore = isUninitialized(); + + initialize@withrevert(); + bool success = !lastReverted; + + assert success <=> isUninitializedBefore, "can only initialize uninitialized contracts"; + assert success => version() == 1, "initialize must set version() to 1"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: Reinitialize correctly sets the version. │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule reinitializeEffects() { + requireInvariant notInitializing(); + + uint8 versionBefore = version(); + + uint8 n; + reinitialize@withrevert(n); + bool success = !lastReverted; + + assert success <=> versionBefore < n, "can only reinitialize to a latter versions"; + assert success => version() == n, "reinitialize must set version() to n"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: Can disable. │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule disableEffect() { + requireInvariant notInitializing(); + + disable@withrevert(); + bool success = !lastReverted; + + assert success, "call to _disableInitializers failed"; + assert isDisabled(), "disable state not set"; +} From 3214f6c2567f0e7938f481b0a6b5cd2fe3b13cdb Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Wed, 8 Mar 2023 23:12:37 +0100 Subject: [PATCH 075/133] Add FV specification for ERC20Wrapper (#4100) Co-authored-by: Francisco --- .changeset/tender-needles-dance.md | 5 + certora/harnesses/ERC20PermitHarness.sol | 3 +- certora/harnesses/ERC20WrapperHarness.sol | 25 +++ certora/run.js | 8 +- certora/specs.json | 12 ++ certora/specs/ERC20Wrapper.spec | 198 ++++++++++++++++++ .../token/ERC20/extensions/ERC20Wrapper.sol | 5 +- 7 files changed, 249 insertions(+), 7 deletions(-) create mode 100644 .changeset/tender-needles-dance.md create mode 100644 certora/harnesses/ERC20WrapperHarness.sol create mode 100644 certora/specs/ERC20Wrapper.spec diff --git a/.changeset/tender-needles-dance.md b/.changeset/tender-needles-dance.md new file mode 100644 index 000000000..d75adec95 --- /dev/null +++ b/.changeset/tender-needles-dance.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': minor +--- + +`ERC20Wrapper`: self wrapping and deposit by the wrapper itself are now explicitelly forbiden. diff --git a/certora/harnesses/ERC20PermitHarness.sol b/certora/harnesses/ERC20PermitHarness.sol index cc66358b2..dd0aacae2 100644 --- a/certora/harnesses/ERC20PermitHarness.sol +++ b/certora/harnesses/ERC20PermitHarness.sol @@ -2,10 +2,9 @@ pragma solidity ^0.8.0; -import "../patched/token/ERC20/ERC20.sol"; import "../patched/token/ERC20/extensions/ERC20Permit.sol"; -contract ERC20PermitHarness is ERC20, ERC20Permit { +contract ERC20PermitHarness is ERC20Permit { constructor(string memory name, string memory symbol) ERC20(name, symbol) ERC20Permit(name) {} function mint(address account, uint256 amount) external { diff --git a/certora/harnesses/ERC20WrapperHarness.sol b/certora/harnesses/ERC20WrapperHarness.sol new file mode 100644 index 000000000..50a96cc17 --- /dev/null +++ b/certora/harnesses/ERC20WrapperHarness.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../patched/token/ERC20/extensions/ERC20Wrapper.sol"; + +contract ERC20WrapperHarness is ERC20Wrapper { + constructor(IERC20 _underlying, string memory _name, string memory _symbol) ERC20(_name, _symbol) ERC20Wrapper(_underlying) {} + + function underlyingTotalSupply() public view returns (uint256) { + return underlying().totalSupply(); + } + + function underlyingBalanceOf(address account) public view returns (uint256) { + return underlying().balanceOf(account); + } + + function underlyingAllowanceToThis(address account) public view returns (uint256) { + return underlying().allowance(account, address(this)); + } + + function recover(address account) public returns (uint256) { + return _recover(account); + } +} diff --git a/certora/run.js b/certora/run.js index 172309e19..f3234c1a3 100644 --- a/certora/run.js +++ b/certora/run.js @@ -31,7 +31,7 @@ if (request) { } for (const { spec, contract, files, options = [] } of Object.values(specs)) { - limit(runCertora, spec, contract, files, [...options, ...extraOptions]); + limit(runCertora, spec, contract, files, [...options.flatMap(opt => opt.split(' ')), ...extraOptions]); } // Run certora, aggregate the output and print it at the end @@ -50,7 +50,7 @@ async function runCertora(spec, contract, files, options = []) { const urls = data.toString('utf8').match(/https?:\S*/g); for (const url of urls ?? []) { if (url.includes('/jobStatus/')) { - console.error(`[${spec}] ${url}`); + console.error(`[${spec}] ${url.replace('/jobStatus/', '/output/')}`); stream.off('data', logStatusUrl); break; } @@ -108,8 +108,8 @@ function writeEntry(spec, contract, success, url) { spec, contract, success ? ':x:' : ':heavy_check_mark:', - `[link](${url})`, - `[link](${url?.replace('/jobStatus/', '/output/')})`, + url ? `[link](${url})` : 'error', + url ? `[link](${url?.replace('/jobStatus/', '/output/')})` : 'error', ), ); } diff --git a/certora/specs.json b/certora/specs.json index 8e4fe21f4..228e85fe4 100644 --- a/certora/specs.json +++ b/certora/specs.json @@ -29,6 +29,18 @@ ], "options": ["--optimistic_loop"] }, + { + "spec": "ERC20Wrapper", + "contract": "ERC20WrapperHarness", + "files": [ + "certora/harnesses/ERC20PermitHarness.sol", + "certora/harnesses/ERC20WrapperHarness.sol" + ], + "options": [ + "--link ERC20WrapperHarness:_underlying=ERC20PermitHarness", + "--optimistic_loop" + ] + }, { "spec": "Initializable", "contract": "InitializableHarness", diff --git a/certora/specs/ERC20Wrapper.spec b/certora/specs/ERC20Wrapper.spec new file mode 100644 index 000000000..c10173766 --- /dev/null +++ b/certora/specs/ERC20Wrapper.spec @@ -0,0 +1,198 @@ +import "helpers.spec" +import "ERC20.spec" + +methods { + underlying() returns(address) envfree + underlyingTotalSupply() returns(uint256) envfree + underlyingBalanceOf(address) returns(uint256) envfree + underlyingAllowanceToThis(address) returns(uint256) envfree + + depositFor(address, uint256) returns(bool) + withdrawTo(address, uint256) returns(bool) + recover(address) returns(uint256) +} + +use invariant totalSupplyIsSumOfBalances + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Helper: consequence of `totalSupplyIsSumOfBalances` applied to underlying │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +function underlyingBalancesLowerThanUnderlyingSupply(address a) returns bool { + return underlyingBalanceOf(a) <= underlyingTotalSupply(); +} + +function sumOfUnderlyingBalancesLowerThanUnderlyingSupply(address a, address b) returns bool { + return a != b => underlyingBalanceOf(a) + underlyingBalanceOf(b) <= underlyingTotalSupply(); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: wrapped token can't be undercollateralized (solvency of the wrapper) │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant totalSupplyIsSmallerThanUnderlyingBalance() + totalSupply() <= underlyingBalanceOf(currentContract) && + underlyingBalanceOf(currentContract) <= underlyingTotalSupply() && + underlyingTotalSupply() <= max_uint256 + { + preserved { + requireInvariant totalSupplyIsSumOfBalances; + require underlyingBalancesLowerThanUnderlyingSupply(currentContract); + } + preserved depositFor(address account, uint256 amount) with (env e) { + require sumOfUnderlyingBalancesLowerThanUnderlyingSupply(e.msg.sender, currentContract); + } + } + +invariant noSelfWrap() + currentContract != underlying() + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: depositFor liveness and effects │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule depositFor(env e) { + require nonpayable(e); + + address sender = e.msg.sender; + address receiver; + address other; + uint256 amount; + + // sanity + requireInvariant noSelfWrap; + requireInvariant totalSupplyIsSumOfBalances; + requireInvariant totalSupplyIsSmallerThanUnderlyingBalance; + require sumOfUnderlyingBalancesLowerThanUnderlyingSupply(currentContract, sender); + + uint256 balanceBefore = balanceOf(receiver); + uint256 supplyBefore = totalSupply(); + uint256 senderUnderlyingBalanceBefore = underlyingBalanceOf(sender); + uint256 senderUnderlyingAllowanceBefore = underlyingAllowanceToThis(sender); + uint256 wrapperUnderlyingBalanceBefore = underlyingBalanceOf(currentContract); + uint256 underlyingSupplyBefore = underlyingTotalSupply(); + + uint256 otherBalanceBefore = balanceOf(other); + uint256 otherUnderlyingBalanceBefore = underlyingBalanceOf(other); + + depositFor@withrevert(e, receiver, amount); + bool success = !lastReverted; + + // liveness + assert success <=> ( + sender != currentContract && // invalid sender + sender != 0 && // invalid sender + receiver != 0 && // invalid receiver + amount <= senderUnderlyingBalanceBefore && // deposit doesn't exceed balance + amount <= senderUnderlyingAllowanceBefore // deposit doesn't exceed allowance + ); + + // effects + assert success => ( + balanceOf(receiver) == balanceBefore + amount && + totalSupply() == supplyBefore + amount && + underlyingBalanceOf(currentContract) == wrapperUnderlyingBalanceBefore + amount && + underlyingBalanceOf(sender) == senderUnderlyingBalanceBefore - amount + ); + + // no side effect + assert underlyingTotalSupply() == underlyingSupplyBefore; + assert balanceOf(other) != otherBalanceBefore => other == receiver; + assert underlyingBalanceOf(other) != otherUnderlyingBalanceBefore => (other == sender || other == currentContract); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: withdrawTo liveness and effects │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule withdrawTo(env e) { + require nonpayable(e); + + address sender = e.msg.sender; + address receiver; + address other; + uint256 amount; + + // sanity + requireInvariant noSelfWrap; + requireInvariant totalSupplyIsSumOfBalances; + requireInvariant totalSupplyIsSmallerThanUnderlyingBalance; + require sumOfUnderlyingBalancesLowerThanUnderlyingSupply(currentContract, receiver); + + uint256 balanceBefore = balanceOf(sender); + uint256 supplyBefore = totalSupply(); + uint256 receiverUnderlyingBalanceBefore = underlyingBalanceOf(receiver); + uint256 wrapperUnderlyingBalanceBefore = underlyingBalanceOf(currentContract); + uint256 underlyingSupplyBefore = underlyingTotalSupply(); + + uint256 otherBalanceBefore = balanceOf(other); + uint256 otherUnderlyingBalanceBefore = underlyingBalanceOf(other); + + withdrawTo@withrevert(e, receiver, amount); + bool success = !lastReverted; + + // liveness + assert success <=> ( + sender != 0 && // invalid sender + receiver != 0 && // invalid receiver + amount <= balanceBefore // withdraw doesn't exceed balance + ); + + // effects + assert success => ( + balanceOf(sender) == balanceBefore - amount && + totalSupply() == supplyBefore - amount && + underlyingBalanceOf(currentContract) == wrapperUnderlyingBalanceBefore - (currentContract != receiver ? amount : 0) && + underlyingBalanceOf(receiver) == receiverUnderlyingBalanceBefore + (currentContract != receiver ? amount : 0) + ); + + // no side effect + assert underlyingTotalSupply() == underlyingSupplyBefore; + assert balanceOf(other) != otherBalanceBefore => other == sender; + assert underlyingBalanceOf(other) != otherUnderlyingBalanceBefore => (other == receiver || other == currentContract); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: recover liveness and effects │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule recover(env e) { + require nonpayable(e); + + address receiver; + address other; + + // sanity + requireInvariant noSelfWrap; + requireInvariant totalSupplyIsSumOfBalances; + requireInvariant totalSupplyIsSmallerThanUnderlyingBalance; + + uint256 value = underlyingBalanceOf(currentContract) - totalSupply(); + uint256 supplyBefore = totalSupply(); + uint256 balanceBefore = balanceOf(receiver); + + uint256 otherBalanceBefore = balanceOf(other); + uint256 otherUnderlyingBalanceBefore = underlyingBalanceOf(other); + + recover@withrevert(e, receiver); + bool success = !lastReverted; + + // liveness + assert success <=> receiver != 0; + + // effect + assert success => ( + balanceOf(receiver) == balanceBefore + value && + totalSupply() == supplyBefore + value && + totalSupply() == underlyingBalanceOf(currentContract) + ); + + // no side effect + assert underlyingBalanceOf(other) == otherUnderlyingBalanceBefore; + assert balanceOf(other) != otherBalanceBefore => other == receiver; +} diff --git a/contracts/token/ERC20/extensions/ERC20Wrapper.sol b/contracts/token/ERC20/extensions/ERC20Wrapper.sol index ce515693e..bfe782e43 100644 --- a/contracts/token/ERC20/extensions/ERC20Wrapper.sol +++ b/contracts/token/ERC20/extensions/ERC20Wrapper.sol @@ -19,6 +19,7 @@ abstract contract ERC20Wrapper is ERC20 { IERC20 private immutable _underlying; constructor(IERC20 underlyingToken) { + require(underlyingToken != this, "ERC20Wrapper: cannot self wrap"); _underlying = underlyingToken; } @@ -44,7 +45,9 @@ abstract contract ERC20Wrapper is ERC20 { * @dev Allow a user to deposit underlying tokens and mint the corresponding number of wrapped tokens. */ function depositFor(address account, uint256 amount) public virtual returns (bool) { - SafeERC20.safeTransferFrom(_underlying, _msgSender(), address(this), amount); + address sender = _msgSender(); + require(sender != address(this), "ERC20Wrapper: wrapper can't deposit"); + SafeERC20.safeTransferFrom(_underlying, sender, address(this), amount); _mint(account, amount); return true; } From 58a62916de431db0756a8f474725f861c30c5f36 Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Thu, 9 Mar 2023 19:41:08 +0200 Subject: [PATCH 076/133] Bump and pin Forge Std submodule (#4102) --- .gitmodules | 1 + lib/forge-std | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index aaa229f8d..08a09bbcf 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,5 @@ [submodule "lib/forge-std"] + branch = v1 path = lib/forge-std url = https://github.com/foundry-rs/forge-std [submodule "lib/erc4626-tests"] diff --git a/lib/forge-std b/lib/forge-std index eb980e1d4..c2236853a 160000 --- a/lib/forge-std +++ b/lib/forge-std @@ -1 +1 @@ -Subproject commit eb980e1d4f0e8173ec27da77297ae411840c8ccb +Subproject commit c2236853aadb8e2d9909bbecdc490099519b70a4 From f8e3c375d19bd12f54222109dd0801c0e0b60dd2 Mon Sep 17 00:00:00 2001 From: Francisco Date: Thu, 9 Mar 2023 17:55:52 -0300 Subject: [PATCH 077/133] Credit YieldBox for virtual offset (#4103) --- docs/modules/ROOT/pages/erc4626.adoc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/modules/ROOT/pages/erc4626.adoc b/docs/modules/ROOT/pages/erc4626.adoc index 00d46a4d0..c8adce736 100644 --- a/docs/modules/ROOT/pages/erc4626.adoc +++ b/docs/modules/ROOT/pages/erc4626.adoc @@ -102,14 +102,13 @@ In this scenario, the attack is stem:[n] times less powerful (in how much it is === Defending with a virtual offset -The defense we propose consists of two parts: +The defense we propose is based on the approach used in link:https://github.com/boringcrypto/YieldBox[YieldBox]. It consists of two parts: - Use an offset between the "precision" of the representation of shares and assets. Said otherwise, we use more decimal places to represent the shares than the underlying token does to represent the assets. - Include virtual shares and virtual assets in the exchange rate computation. These virtual assets enforce the conversion rate when the vault is empty. These two parts work together in enforcing the security of the vault. First, the increased precision corresponds to a high rate, which we saw is safer as it reduces the rounding error when computing the amount of shares. Second, the virtual assets and shares (in addition to simplifying a lot of the computations) capture part of the donation, making it unprofitable for a developer to perform an attack. - Following the previous math definitions, we have: - stem:[\delta] the vault offset From 6794c9460bd557bde71fb71b595369d86728c3ee Mon Sep 17 00:00:00 2001 From: Francisco Date: Mon, 13 Mar 2023 12:45:58 -0300 Subject: [PATCH 078/133] Run formal verification when label is added (#4112) --- .github/workflows/formal-verification.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/formal-verification.yml b/.github/workflows/formal-verification.yml index 6c9935ad4..a1b3b6e6d 100644 --- a/.github/workflows/formal-verification.yml +++ b/.github/workflows/formal-verification.yml @@ -5,7 +5,12 @@ on: branches: - master - release-v* - pull_request: {} + pull_request: + types: + - opened + - reopened + - synchronize + - labeled workflow_dispatch: {} env: From e739144cb02dbbd73256a2ae79f024faf3c7ea0a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 13 Mar 2023 18:31:24 -0300 Subject: [PATCH 079/133] Update dependency certora-cli to v3.6.4 (#4110) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Francisco --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 797b3598d..da3e95766 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -certora-cli==3.6.3 +certora-cli==3.6.4 From e69248e551482db39bcd54031e85f769718af587 Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Mon, 13 Mar 2023 21:05:14 -0300 Subject: [PATCH 080/133] Limit concurrency of formal-verification runs --- .github/workflows/formal-verification.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/formal-verification.yml b/.github/workflows/formal-verification.yml index a1b3b6e6d..29c02541c 100644 --- a/.github/workflows/formal-verification.yml +++ b/.github/workflows/formal-verification.yml @@ -18,6 +18,8 @@ env: JAVA_VERSION: '11' SOLC_VERSION: '0.8.19' +concurrency: ${{ github.workflow }}-${{ github.ref }} + jobs: apply-diff: runs-on: ubuntu-latest From ea2d5ad2e780ed8cfa6f59c5942dce070ff14d72 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 13 Mar 2023 21:09:01 -0300 Subject: [PATCH 081/133] Update lockfile (#4080) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package-lock.json | 814 ++++++++++++++++++++++++++-------------------- 1 file changed, 456 insertions(+), 358 deletions(-) diff --git a/package-lock.json b/package-lock.json index b9b491e05..f44a1b939 100644 --- a/package-lock.json +++ b/package-lock.json @@ -499,15 +499,39 @@ "deprecated": "Please use @ensdomains/ens-contracts", "dev": true }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.2.0.tgz", + "integrity": "sha512-gB8T4H4DEfX2IV9zGDJPOBgP1e/DbfCPDTtEqUMckpvzS1OYtva8JdFYBqMwYk7xAQ429WGF/UPqn8uQ//h2vQ==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.4.0.tgz", + "integrity": "sha512-A9983Q0LnDGdLPjxyXQ00sbV+K+O+ko2Dr+CZigbHWtX9pNfxlaBkMR8X1CztI73zuEyEBXTVjx7CE+/VSwDiQ==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", - "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.1.tgz", + "integrity": "sha512-eFRmABvW2E5Ho6f5fHLqgena46rOj7r7OKHYfLElqcBfGFHHpjBhivyi5+jOEQuSpdc/1phIZJlbC2te+tZNIw==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.4.0", + "espree": "^9.5.0", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -540,6 +564,15 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/@eslint/js": { + "version": "8.36.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.36.0.tgz", + "integrity": "sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, "node_modules/@ethereumjs/common": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.5.0.tgz", @@ -1698,30 +1731,30 @@ } }, "node_modules/@nomicfoundation/solidity-analyzer": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.0.tgz", - "integrity": "sha512-xGWAiVCGOycvGiP/qrlf9f9eOn7fpNbyJygcB0P21a1MDuVPlKt0Srp7rvtBEutYQ48ouYnRXm33zlRnlTOPHg==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.1.tgz", + "integrity": "sha512-1LMtXj1puAxyFusBgUIy5pZk3073cNXYnXUpuNKFghHbIit/xZgbk0AokpUADbNm3gyD6bFWl3LRFh3dhVdREg==", "dev": true, "engines": { "node": ">= 12" }, "optionalDependencies": { - "@nomicfoundation/solidity-analyzer-darwin-arm64": "0.1.0", - "@nomicfoundation/solidity-analyzer-darwin-x64": "0.1.0", - "@nomicfoundation/solidity-analyzer-freebsd-x64": "0.1.0", - "@nomicfoundation/solidity-analyzer-linux-arm64-gnu": "0.1.0", - "@nomicfoundation/solidity-analyzer-linux-arm64-musl": "0.1.0", - "@nomicfoundation/solidity-analyzer-linux-x64-gnu": "0.1.0", - "@nomicfoundation/solidity-analyzer-linux-x64-musl": "0.1.0", - "@nomicfoundation/solidity-analyzer-win32-arm64-msvc": "0.1.0", - "@nomicfoundation/solidity-analyzer-win32-ia32-msvc": "0.1.0", - "@nomicfoundation/solidity-analyzer-win32-x64-msvc": "0.1.0" + "@nomicfoundation/solidity-analyzer-darwin-arm64": "0.1.1", + "@nomicfoundation/solidity-analyzer-darwin-x64": "0.1.1", + "@nomicfoundation/solidity-analyzer-freebsd-x64": "0.1.1", + "@nomicfoundation/solidity-analyzer-linux-arm64-gnu": "0.1.1", + "@nomicfoundation/solidity-analyzer-linux-arm64-musl": "0.1.1", + "@nomicfoundation/solidity-analyzer-linux-x64-gnu": "0.1.1", + "@nomicfoundation/solidity-analyzer-linux-x64-musl": "0.1.1", + "@nomicfoundation/solidity-analyzer-win32-arm64-msvc": "0.1.1", + "@nomicfoundation/solidity-analyzer-win32-ia32-msvc": "0.1.1", + "@nomicfoundation/solidity-analyzer-win32-x64-msvc": "0.1.1" } }, "node_modules/@nomicfoundation/solidity-analyzer-darwin-arm64": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.0.tgz", - "integrity": "sha512-vEF3yKuuzfMHsZecHQcnkUrqm8mnTWfJeEVFHpg+cO+le96xQA4lAJYdUan8pXZohQxv1fSReQsn4QGNuBNuCw==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.1.tgz", + "integrity": "sha512-KcTodaQw8ivDZyF+D76FokN/HdpgGpfjc/gFCImdLUyqB6eSWVaZPazMbeAjmfhx3R0zm/NYVzxwAokFKgrc0w==", "cpu": [ "arm64" ], @@ -1735,9 +1768,9 @@ } }, "node_modules/@nomicfoundation/solidity-analyzer-darwin-x64": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.0.tgz", - "integrity": "sha512-dlHeIg0pTL4dB1l9JDwbi/JG6dHQaU1xpDK+ugYO8eJ1kxx9Dh2isEUtA4d02cQAl22cjOHTvifAk96A+ItEHA==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.1.tgz", + "integrity": "sha512-XhQG4BaJE6cIbjAVtzGOGbK3sn1BO9W29uhk9J8y8fZF1DYz0Doj8QDMfpMu+A6TjPDs61lbsmeYodIDnfveSA==", "cpu": [ "x64" ], @@ -1751,9 +1784,9 @@ } }, "node_modules/@nomicfoundation/solidity-analyzer-freebsd-x64": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-freebsd-x64/-/solidity-analyzer-freebsd-x64-0.1.0.tgz", - "integrity": "sha512-WFCZYMv86WowDA4GiJKnebMQRt3kCcFqHeIomW6NMyqiKqhK1kIZCxSLDYsxqlx396kKLPN1713Q1S8tu68GKg==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-freebsd-x64/-/solidity-analyzer-freebsd-x64-0.1.1.tgz", + "integrity": "sha512-GHF1VKRdHW3G8CndkwdaeLkVBi5A9u2jwtlS7SLhBc8b5U/GcoL39Q+1CSO3hYqePNP+eV5YI7Zgm0ea6kMHoA==", "cpu": [ "x64" ], @@ -1767,9 +1800,9 @@ } }, "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-gnu": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.0.tgz", - "integrity": "sha512-DTw6MNQWWlCgc71Pq7CEhEqkb7fZnS7oly13pujs4cMH1sR0JzNk90Mp1zpSCsCs4oKan2ClhMlLKtNat/XRKQ==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.1.tgz", + "integrity": "sha512-g4Cv2fO37ZsUENQ2vwPnZc2zRenHyAxHcyBjKcjaSmmkKrFr64yvzeNO8S3GBFCo90rfochLs99wFVGT/0owpg==", "cpu": [ "arm64" ], @@ -1783,9 +1816,9 @@ } }, "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-musl": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.0.tgz", - "integrity": "sha512-wUpUnR/3GV5Da88MhrxXh/lhb9kxh9V3Jya2NpBEhKDIRCDmtXMSqPMXHZmOR9DfCwCvG6vLFPr/+YrPCnUN0w==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.1.tgz", + "integrity": "sha512-WJ3CE5Oek25OGE3WwzK7oaopY8xMw9Lhb0mlYuJl/maZVo+WtP36XoQTb7bW/i8aAdHW5Z+BqrHMux23pvxG3w==", "cpu": [ "arm64" ], @@ -1799,9 +1832,9 @@ } }, "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-gnu": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.0.tgz", - "integrity": "sha512-lR0AxK1x/MeKQ/3Pt923kPvwigmGX3OxeU5qNtQ9pj9iucgk4PzhbS3ruUeSpYhUxG50jN4RkIGwUMoev5lguw==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.1.tgz", + "integrity": "sha512-5WN7leSr5fkUBBjE4f3wKENUy9HQStu7HmWqbtknfXkkil+eNWiBV275IOlpXku7v3uLsXTOKpnnGHJYI2qsdA==", "cpu": [ "x64" ], @@ -1815,9 +1848,9 @@ } }, "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-musl": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.0.tgz", - "integrity": "sha512-A1he/8gy/JeBD3FKvmI6WUJrGrI5uWJNr5Xb9WdV+DK0F8msuOqpEByLlnTdLkXMwW7nSl3awvLezOs9xBHJEg==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.1.tgz", + "integrity": "sha512-KdYMkJOq0SYPQMmErv/63CwGwMm5XHenEna9X9aB8mQmhDBrYrlAOSsIPgFCUSL0hjxE3xHP65/EPXR/InD2+w==", "cpu": [ "x64" ], @@ -1831,9 +1864,9 @@ } }, "node_modules/@nomicfoundation/solidity-analyzer-win32-arm64-msvc": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-arm64-msvc/-/solidity-analyzer-win32-arm64-msvc-0.1.0.tgz", - "integrity": "sha512-7x5SXZ9R9H4SluJZZP8XPN+ju7Mx+XeUMWZw7ZAqkdhP5mK19I4vz3x0zIWygmfE8RT7uQ5xMap0/9NPsO+ykw==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-arm64-msvc/-/solidity-analyzer-win32-arm64-msvc-0.1.1.tgz", + "integrity": "sha512-VFZASBfl4qiBYwW5xeY20exWhmv6ww9sWu/krWSesv3q5hA0o1JuzmPHR4LPN6SUZj5vcqci0O6JOL8BPw+APg==", "cpu": [ "arm64" ], @@ -1847,9 +1880,9 @@ } }, "node_modules/@nomicfoundation/solidity-analyzer-win32-ia32-msvc": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-ia32-msvc/-/solidity-analyzer-win32-ia32-msvc-0.1.0.tgz", - "integrity": "sha512-m7w3xf+hnE774YRXu+2mGV7RiF3QJtUoiYU61FascCkQhX3QMQavh7saH/vzb2jN5D24nT/jwvaHYX/MAM9zUw==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-ia32-msvc/-/solidity-analyzer-win32-ia32-msvc-0.1.1.tgz", + "integrity": "sha512-JnFkYuyCSA70j6Si6cS1A9Gh1aHTEb8kOTBApp/c7NRTFGNMH8eaInKlyuuiIbvYFhlXW4LicqyYuWNNq9hkpQ==", "cpu": [ "ia32" ], @@ -1863,9 +1896,9 @@ } }, "node_modules/@nomicfoundation/solidity-analyzer-win32-x64-msvc": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.0.tgz", - "integrity": "sha512-xCuybjY0sLJQnJhupiFAXaek2EqF0AP0eBjgzaalPXSNvCEN6ZYHvUzdA50ENDVeSYFXcUsYf3+FsD3XKaeptA==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.1.tgz", + "integrity": "sha512-HrVJr6+WjIXGnw3Q9u6KQcbZCtk0caVWhCdFADySvRyUxJ8PnzlaP+MhwNE8oyT8OZ6ejHBRrrgjSqDCFXGirw==", "cpu": [ "x64" ], @@ -2082,9 +2115,9 @@ } }, "node_modules/@openzeppelin/upgrades-core": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades-core/-/upgrades-core-1.24.0.tgz", - "integrity": "sha512-lXf1tUrCZ3Q/YmWhw0cuSSOHMp0OAsmeOg1fhSGEM6nQQ6cIVlFvq2pCV5hZMb7xkOm5pmmzV8JW1W3kfW6Lfw==", + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades-core/-/upgrades-core-1.24.1.tgz", + "integrity": "sha512-QhdIQDUykJ3vQauB6CheV7vk4zgn0e1iY+IDg7r1KqpA1m2bqIGjQCpzidW33K4bZc9zdJSPx2/Z6Um5KxCB7A==", "dev": true, "dependencies": { "cbor": "^8.0.0", @@ -2347,9 +2380,9 @@ } }, "node_modules/@truffle/abi-utils": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/@truffle/abi-utils/-/abi-utils-0.3.8.tgz", - "integrity": "sha512-RevMtlEuQw9cE2VWzQuvLDSYPCVSZQQUOsaK8ArcwxXct6ugiJCDC7tNouhHzP1Y4ccdZtG2y/XPHQJdzgYdZQ==", + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@truffle/abi-utils/-/abi-utils-0.3.9.tgz", + "integrity": "sha512-G5dqgwRHx5zwlXjz3QT8OJVfB2cOqWwD6DwKso0KttUt/zejhCjnkKq72rSgyeLMkz7wBB9ERLOsupLBILM8MA==", "dev": true, "dependencies": { "change-case": "3.0.2", @@ -2364,13 +2397,13 @@ "dev": true }, "node_modules/@truffle/codec": { - "version": "0.14.15", - "resolved": "https://registry.npmjs.org/@truffle/codec/-/codec-0.14.15.tgz", - "integrity": "sha512-cooWy8blmvYQQRBKgzWJnDUS6mZE9cvnmpVN15jU6TseAQkBtmfYfCH12QCKEWMq2+R4yQICP54WNCYg78g72g==", + "version": "0.14.16", + "resolved": "https://registry.npmjs.org/@truffle/codec/-/codec-0.14.16.tgz", + "integrity": "sha512-a9UY3n/FnkKN3Q4zOuMFOOcLWb80mdknj+voim4vvXYtJm1aAZQZE5sG9aLnMBTl4TiGLzUtfNDVYY7WgWgDag==", "dev": true, "dependencies": { - "@truffle/abi-utils": "^0.3.8", - "@truffle/compile-common": "^0.9.3", + "@truffle/abi-utils": "^0.3.9", + "@truffle/compile-common": "^0.9.4", "big.js": "^6.0.3", "bn.js": "^5.1.3", "cbor": "^5.2.0", @@ -2452,9 +2485,9 @@ "dev": true }, "node_modules/@truffle/compile-common": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/@truffle/compile-common/-/compile-common-0.9.3.tgz", - "integrity": "sha512-9S86H5DRC0zEj164KeClP/6jVt1M/nRd7St89h6QbuIU0JjpqSz1SXpkvqhbFoV9hhW+4ZGh0NysjrdPlk7gFw==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/@truffle/compile-common/-/compile-common-0.9.4.tgz", + "integrity": "sha512-mnqJB/hLiPHNf+WKwt/2MH6lv34xSG/SFCib7+ckAklutUqVLeFo8EwQxinuHNkU7LY0C+YgZXhK1WTCO5YRJQ==", "dev": true, "dependencies": { "@truffle/error": "^0.2.0", @@ -2468,17 +2501,17 @@ "dev": true }, "node_modules/@truffle/contract": { - "version": "4.6.15", - "resolved": "https://registry.npmjs.org/@truffle/contract/-/contract-4.6.15.tgz", - "integrity": "sha512-3V+50z94XRh+I3axz6Zrot1wlMhRiG2O9XjR20LwR5YBnzHV7YFfOs8x6pluXVLQyxcVJBISJyqxvGxpkecrZg==", + "version": "4.6.17", + "resolved": "https://registry.npmjs.org/@truffle/contract/-/contract-4.6.17.tgz", + "integrity": "sha512-sIMam5Wqr9AEiqHfOcWGJGqTv8Qy+BT765PaNHUUT6JBAY+tpHM3FlQd2nM6zLJ8paR3SLDGIthkhCBH/KNgDA==", "dev": true, "dependencies": { "@ensdomains/ensjs": "^2.1.0", "@truffle/blockchain-utils": "^0.1.6", - "@truffle/contract-schema": "^3.4.12", - "@truffle/debug-utils": "^6.0.46", + "@truffle/contract-schema": "^3.4.13", + "@truffle/debug-utils": "^6.0.47", "@truffle/error": "^0.2.0", - "@truffle/interface-adapter": "^0.5.29", + "@truffle/interface-adapter": "^0.5.30", "bignumber.js": "^7.2.1", "debug": "^4.3.1", "ethers": "^4.0.32", @@ -2490,9 +2523,9 @@ } }, "node_modules/@truffle/contract-schema": { - "version": "3.4.12", - "resolved": "https://registry.npmjs.org/@truffle/contract-schema/-/contract-schema-3.4.12.tgz", - "integrity": "sha512-XpMMps/bqHwiRuCyLiEEGWEAvGGzGj4u1X1+lzxrtIsrwbQhSZcdgEbXl9vGxOOJWOup3HXRCIsjlao27kS4OA==", + "version": "3.4.13", + "resolved": "https://registry.npmjs.org/@truffle/contract-schema/-/contract-schema-3.4.13.tgz", + "integrity": "sha512-emG7upuryYFrsPDbHqeASPWXL824M1tinhQwSPG0phSoa3g+RX9fUNNN/VPmF3tSkXLWUMhRnb7ehxnaCuRbZg==", "dev": true, "dependencies": { "ajv": "^6.10.0", @@ -2506,12 +2539,12 @@ "dev": true }, "node_modules/@truffle/debug-utils": { - "version": "6.0.46", - "resolved": "https://registry.npmjs.org/@truffle/debug-utils/-/debug-utils-6.0.46.tgz", - "integrity": "sha512-MWko3c1M0NI8IT0yNh8Dh2xoDgR2R1apP8hc/9VsR/4Q7P6OE/578WRpZnvo2HWXYBiJ2PrWBDtMYBHntImrrA==", + "version": "6.0.47", + "resolved": "https://registry.npmjs.org/@truffle/debug-utils/-/debug-utils-6.0.47.tgz", + "integrity": "sha512-bUjdzLPdEKtoUCDzaXkrOoi+PbyAJlMBzGequBK8tirT7xL9bCP2Pd/WxvnmRd7AnfroxGNvXwVXWTItW5SMWQ==", "dev": true, "dependencies": { - "@truffle/codec": "^0.14.15", + "@truffle/codec": "^0.14.16", "@trufflesuite/chromafi": "^3.0.0", "bn.js": "^5.1.3", "chalk": "^2.4.2", @@ -2532,9 +2565,9 @@ "dev": true }, "node_modules/@truffle/interface-adapter": { - "version": "0.5.29", - "resolved": "https://registry.npmjs.org/@truffle/interface-adapter/-/interface-adapter-0.5.29.tgz", - "integrity": "sha512-6UlJ+f87z7y/dWk9UfbIU+4e80iRsp8h03LEiE5B+PvZbr6cuMjLJUBtBBQZMo3+xrIcS/2u3p5hOxW8OJm8tw==", + "version": "0.5.30", + "resolved": "https://registry.npmjs.org/@truffle/interface-adapter/-/interface-adapter-0.5.30.tgz", + "integrity": "sha512-wyCcESeZJBkAfuSGU8GHCusIWDUDyQjJZMcyShv59ZTSAwQR7xx0+a0Q1LlS532G/pGFLYe2VzKSY1pRHRwgug==", "dev": true, "dependencies": { "bn.js": "^5.1.3", @@ -3006,6 +3039,19 @@ "sprintf-js": "~1.0.2" } }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -3367,6 +3413,21 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, + "node_modules/body-parser/node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", @@ -4227,9 +4288,9 @@ } }, "node_modules/cosmiconfig": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.0.0.tgz", - "integrity": "sha512-da1EafcpH6b/TD8vDRaWV7xFINlHlF6zKsGwS1TsuVJTZRkquaS5HTMq7uq6h31619QjbsYl21gVDOm32KM1vQ==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.1.0.tgz", + "integrity": "sha512-0tLZ9URlPGU7JsKq0DQOQ3FoRsYX8xDZ7xMiATQfaiGMz7EHowNkbU9u1coAOmnh9p/1ySpm0RB3JNWRXM5GCg==", "dev": true, "dependencies": { "import-fresh": "^3.2.1", @@ -4239,6 +4300,9 @@ }, "engines": { "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" } }, "node_modules/cosmiconfig/node_modules/argparse": { @@ -4881,18 +4945,18 @@ } }, "node_modules/es-abstract": { - "version": "1.21.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.1.tgz", - "integrity": "sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==", + "version": "1.21.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz", + "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==", "dev": true, "dependencies": { + "array-buffer-byte-length": "^1.0.0", "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", "es-set-tostringtag": "^2.0.1", "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.3", + "get-intrinsic": "^1.2.0", "get-symbol-description": "^1.0.0", "globalthis": "^1.0.3", "gopd": "^1.0.1", @@ -4900,8 +4964,8 @@ "has-property-descriptors": "^1.0.0", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", - "internal-slot": "^1.0.4", - "is-array-buffer": "^3.0.1", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", "is-callable": "^1.2.7", "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", @@ -4909,11 +4973,12 @@ "is-string": "^1.0.7", "is-typed-array": "^1.1.10", "is-weakref": "^1.0.2", - "object-inspect": "^1.12.2", + "object-inspect": "^1.12.3", "object-keys": "^1.1.1", "object.assign": "^4.1.4", "regexp.prototype.flags": "^1.4.3", "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.7", "string.prototype.trimend": "^1.0.6", "string.prototype.trimstart": "^1.0.6", "typed-array-length": "^1.0.4", @@ -5135,12 +5200,15 @@ } }, "node_modules/eslint": { - "version": "8.34.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.34.0.tgz", - "integrity": "sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==", + "version": "8.36.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.36.0.tgz", + "integrity": "sha512-Y956lmS7vDqomxlaaQAHVmeb4tNMp2FWIvU/RnU5BD3IKMD/MJPr76xdyr68P8tV1iNMvN2mRK0yy3c+UjL+bw==", "dev": true, "dependencies": { - "@eslint/eslintrc": "^1.4.1", + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "@eslint/eslintrc": "^2.0.1", + "@eslint/js": "8.36.0", "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -5151,10 +5219,9 @@ "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", + "espree": "^9.5.0", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", @@ -5175,7 +5242,6 @@ "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.1", - "regexpp": "^3.2.0", "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" @@ -5191,9 +5257,9 @@ } }, "node_modules/eslint-config-prettier": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.6.0.tgz", - "integrity": "sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.7.0.tgz", + "integrity": "sha512-HHVXLSlVUhMSmyW4ZzEuvjpwqamgmlfkutD53cYXLikh4pt/modINRcCIApJ84czDxM4GZInwUrromsDdTImTA==", "dev": true, "bin": { "eslint-config-prettier": "bin/cli.js" @@ -5215,33 +5281,6 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/eslint-visitor-keys": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", @@ -5431,9 +5470,9 @@ } }, "node_modules/espree": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", - "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.0.tgz", + "integrity": "sha512-JPbJGhKc47++oo4JkEoTe2wjy4fmMwvFpgJT9cQzmfXKp22Dr6Hf1tdCteLz1h0P3t+mGvWZ+4Uankvh8+c6zw==", "dev": true, "dependencies": { "acorn": "^8.8.0", @@ -5461,9 +5500,9 @@ } }, "node_modules/esquery": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.2.tgz", - "integrity": "sha512-JVSoLdTlTDkmjFmab7H/9SL9qGSyjElT3myyKp7krqjVFQCDLmj1QFaCLRFBszBKI0XVZaiiXvuPIX3ZwHe1Ng==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, "dependencies": { "estraverse": "^5.1.0" @@ -6422,6 +6461,21 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, + "node_modules/express/node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/express/node_modules/raw-body": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", @@ -7203,9 +7257,9 @@ } }, "node_modules/hardhat": { - "version": "2.12.7", - "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.12.7.tgz", - "integrity": "sha512-voWoN6zn5d8BOEaczSyK/1PyfdeOeI3SbGCFb36yCHTJUt6OIqLb+ZDX30VhA1UsYKzLqG7UnWl3fKJUuANc6A==", + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.13.0.tgz", + "integrity": "sha512-ZlzBOLML1QGlm6JWyVAG8lVTEAoOaVm1in/RU2zoGAnYEoD1Rp4T+ZMvrLNhHaaeS9hfjJ1gJUBfiDr4cx+htQ==", "dev": true, "dependencies": { "@ethersproject/abi": "^5.1.2", @@ -7260,10 +7314,10 @@ "ws": "^7.4.6" }, "bin": { - "hardhat": "internal/cli/cli.js" + "hardhat": "internal/cli/bootstrap.js" }, "engines": { - "node": "^14.0.0 || ^16.0.0 || ^18.0.0" + "node": ">=14.0.0" }, "peerDependencies": { "ts-node": "*", @@ -7884,9 +7938,9 @@ } }, "node_modules/immutable": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.2.4.tgz", - "integrity": "sha512-WDxL3Hheb1JkRN3sQkyujNlL/xRjAo3rJtaU5xeufUauG66JdMr32bLj4gF+vWl84DIA3Zxw7tiAjneYzRRw+w==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz", + "integrity": "sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg==", "dev": true }, "node_modules/import-fresh": { @@ -8021,13 +8075,13 @@ } }, "node_modules/is-array-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.1.tgz", - "integrity": "sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", + "get-intrinsic": "^1.2.0", "is-typed-array": "^1.1.10" }, "funding": { @@ -10512,12 +10566,12 @@ } }, "node_modules/prettier-plugin-solidity": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.1.2.tgz", - "integrity": "sha512-KC5oNbFJfyBaFiO0kl56J6AXnDmr9tUlBV1iqo864x4KQrKYKaBZvW9jhT2oC0NHoNp7/GoMJNxqL8pp8k7C/g==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.1.3.tgz", + "integrity": "sha512-fQ9yucPi2sBbA2U2Xjh6m4isUTJ7S7QLc/XDDsktqqxYfTwdYKJ0EnnywXHwCGAaYbQNK+HIYPL1OemxuMsgeg==", "dev": true, "dependencies": { - "@solidity-parser/parser": "^0.15.0", + "@solidity-parser/parser": "^0.16.0", "semver": "^7.3.8", "solidity-comments-extractor": "^0.0.7" }, @@ -10529,9 +10583,9 @@ } }, "node_modules/prettier-plugin-solidity/node_modules/@solidity-parser/parser": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.15.0.tgz", - "integrity": "sha512-5UFJJTzWi1hgFk6aGCZ5rxG2DJkCJOzJ74qg7UkWSNCDSigW+CJLoYUb5bLiKrtI34Nr9rpFSUNHfkqtlL+N/w==", + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.16.0.tgz", + "integrity": "sha512-ESipEcHyRHg4Np4SqBCfcXwyxxna1DgFVz69bgpLV8vzl/NP1DtcKsJ4dJZXWQhY/Z4J2LeKBiOkOVZn9ct33Q==", "dev": true, "dependencies": { "antlr4ts": "^0.5.0-alpha.4" @@ -10633,9 +10687,9 @@ ] }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.1.tgz", + "integrity": "sha512-0wsrzgTz/kAVIeuxSjnpGC56rzYtr6JT/2BwEvMaPhFIoYa1aGO8LbzuU1R0uUYQkLpWBTOj0l/CLAJB64J6nQ==", "dev": true, "dependencies": { "side-channel": "^1.0.4" @@ -10789,9 +10843,9 @@ } }, "node_modules/readable-stream": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.1.tgz", - "integrity": "sha512-+rQmrWMYGA90yenhTYsLWAsLsqVC8osOw6PKE1HDYiO0gdPeKe/xDHNzIAIn4C91YQ6oenEhfYqqc1883qHbjQ==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, "dependencies": { "inherits": "^2.0.3", @@ -10886,18 +10940,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, "node_modules/req-cwd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/req-cwd/-/req-cwd-2.0.0.tgz", @@ -12240,12 +12282,12 @@ } }, "node_modules/solhint": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/solhint/-/solhint-3.4.0.tgz", - "integrity": "sha512-FYEs/LoTxMsWFP/OGsEqR1CBDn3Bn7hrTWsgtjai17MzxITgearIdlo374KKZjjIycu8E2xBcJ+RSWeoBvQmkw==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/solhint/-/solhint-3.4.1.tgz", + "integrity": "sha512-pzZn2RlZhws1XwvLPVSsxfHrwsteFf5eySOhpAytzXwKQYbTCJV6z8EevYDiSVKMpWrvbKpEtJ055CuEmzp4Xg==", "dev": true, "dependencies": { - "@solidity-parser/parser": "^0.15.0", + "@solidity-parser/parser": "^0.16.0", "ajv": "^6.12.6", "antlr4": "^4.11.0", "ast-parents": "^0.0.1", @@ -12271,9 +12313,9 @@ } }, "node_modules/solhint/node_modules/@solidity-parser/parser": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.15.0.tgz", - "integrity": "sha512-5UFJJTzWi1hgFk6aGCZ5rxG2DJkCJOzJ74qg7UkWSNCDSigW+CJLoYUb5bLiKrtI34Nr9rpFSUNHfkqtlL+N/w==", + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.16.0.tgz", + "integrity": "sha512-ESipEcHyRHg4Np4SqBCfcXwyxxna1DgFVz69bgpLV8vzl/NP1DtcKsJ4dJZXWQhY/Z4J2LeKBiOkOVZn9ct33Q==", "dev": true, "dependencies": { "antlr4ts": "^0.5.0-alpha.4" @@ -13113,9 +13155,9 @@ } }, "node_modules/solidity-docgen": { - "version": "0.6.0-beta.34", - "resolved": "https://registry.npmjs.org/solidity-docgen/-/solidity-docgen-0.6.0-beta.34.tgz", - "integrity": "sha512-igdGrkg8gT1jn+B2NwzjEtSf+7NTrSi/jz88zO7MZWgETmcWbXaxgAsQP4BQeC4YFeH0Pie1NsLP7+9qDgvFtA==", + "version": "0.6.0-beta.35", + "resolved": "https://registry.npmjs.org/solidity-docgen/-/solidity-docgen-0.6.0-beta.35.tgz", + "integrity": "sha512-9QdwK1THk/MWIdq1PEW/6dvtND0pUqpFTsbKwwU9YQIMYuRhH1lek9SsgnsGGYtdJ0VTrXXcVT30q20a8Y610A==", "dev": true, "dependencies": { "handlebars": "^4.7.7", @@ -13228,9 +13270,9 @@ "dev": true }, "node_modules/spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", "dev": true, "dependencies": { "spdx-expression-parse": "^3.0.0", @@ -13254,9 +13296,9 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", - "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", + "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==", "dev": true }, "node_modules/sprintf-js": { @@ -13384,6 +13426,23 @@ "node": ">=4" } }, + "node_modules/string.prototype.trim": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", + "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/string.prototype.trimend": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", @@ -14161,9 +14220,9 @@ "dev": true }, "node_modules/undici": { - "version": "5.20.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.20.0.tgz", - "integrity": "sha512-J3j60dYzuo6Eevbawwp1sdg16k5Tf768bxYK4TUJRH7cBM4kFCbf3mOnM/0E3vQYXvpxITbbWmBafaDbxLDz3g==", + "version": "5.21.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.21.0.tgz", + "integrity": "sha512-HOjK8l6a57b2ZGXOcUsI5NLfoTrfmbOl90ixJDl0AEFG4wgHNDQxtZy15/ZQp7HhjkpaGlp/eneMgtsu1dIlUA==", "dev": true, "dependencies": { "busboy": "^1.6.0" @@ -15628,15 +15687,30 @@ "integrity": "sha512-bvaTH34PMCbv6anRa9I/0zjLJgY4EuznbEMgbV77JBCQ9KNC46rzi0avuxpOfu+xDjPEtSFGqVEOr5GlUSGudA==", "dev": true }, + "@eslint-community/eslint-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.2.0.tgz", + "integrity": "sha512-gB8T4H4DEfX2IV9zGDJPOBgP1e/DbfCPDTtEqUMckpvzS1OYtva8JdFYBqMwYk7xAQ429WGF/UPqn8uQ//h2vQ==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^3.3.0" + } + }, + "@eslint-community/regexpp": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.4.0.tgz", + "integrity": "sha512-A9983Q0LnDGdLPjxyXQ00sbV+K+O+ko2Dr+CZigbHWtX9pNfxlaBkMR8X1CztI73zuEyEBXTVjx7CE+/VSwDiQ==", + "dev": true + }, "@eslint/eslintrc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", - "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.1.tgz", + "integrity": "sha512-eFRmABvW2E5Ho6f5fHLqgena46rOj7r7OKHYfLElqcBfGFHHpjBhivyi5+jOEQuSpdc/1phIZJlbC2te+tZNIw==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.4.0", + "espree": "^9.5.0", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -15662,6 +15736,12 @@ } } }, + "@eslint/js": { + "version": "8.36.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.36.0.tgz", + "integrity": "sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg==", + "dev": true + }, "@ethereumjs/common": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.5.0.tgz", @@ -16443,90 +16523,90 @@ } }, "@nomicfoundation/solidity-analyzer": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.0.tgz", - "integrity": "sha512-xGWAiVCGOycvGiP/qrlf9f9eOn7fpNbyJygcB0P21a1MDuVPlKt0Srp7rvtBEutYQ48ouYnRXm33zlRnlTOPHg==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.1.tgz", + "integrity": "sha512-1LMtXj1puAxyFusBgUIy5pZk3073cNXYnXUpuNKFghHbIit/xZgbk0AokpUADbNm3gyD6bFWl3LRFh3dhVdREg==", "dev": true, "requires": { - "@nomicfoundation/solidity-analyzer-darwin-arm64": "0.1.0", - "@nomicfoundation/solidity-analyzer-darwin-x64": "0.1.0", - "@nomicfoundation/solidity-analyzer-freebsd-x64": "0.1.0", - "@nomicfoundation/solidity-analyzer-linux-arm64-gnu": "0.1.0", - "@nomicfoundation/solidity-analyzer-linux-arm64-musl": "0.1.0", - "@nomicfoundation/solidity-analyzer-linux-x64-gnu": "0.1.0", - "@nomicfoundation/solidity-analyzer-linux-x64-musl": "0.1.0", - "@nomicfoundation/solidity-analyzer-win32-arm64-msvc": "0.1.0", - "@nomicfoundation/solidity-analyzer-win32-ia32-msvc": "0.1.0", - "@nomicfoundation/solidity-analyzer-win32-x64-msvc": "0.1.0" + "@nomicfoundation/solidity-analyzer-darwin-arm64": "0.1.1", + "@nomicfoundation/solidity-analyzer-darwin-x64": "0.1.1", + "@nomicfoundation/solidity-analyzer-freebsd-x64": "0.1.1", + "@nomicfoundation/solidity-analyzer-linux-arm64-gnu": "0.1.1", + "@nomicfoundation/solidity-analyzer-linux-arm64-musl": "0.1.1", + "@nomicfoundation/solidity-analyzer-linux-x64-gnu": "0.1.1", + "@nomicfoundation/solidity-analyzer-linux-x64-musl": "0.1.1", + "@nomicfoundation/solidity-analyzer-win32-arm64-msvc": "0.1.1", + "@nomicfoundation/solidity-analyzer-win32-ia32-msvc": "0.1.1", + "@nomicfoundation/solidity-analyzer-win32-x64-msvc": "0.1.1" } }, "@nomicfoundation/solidity-analyzer-darwin-arm64": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.0.tgz", - "integrity": "sha512-vEF3yKuuzfMHsZecHQcnkUrqm8mnTWfJeEVFHpg+cO+le96xQA4lAJYdUan8pXZohQxv1fSReQsn4QGNuBNuCw==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.1.tgz", + "integrity": "sha512-KcTodaQw8ivDZyF+D76FokN/HdpgGpfjc/gFCImdLUyqB6eSWVaZPazMbeAjmfhx3R0zm/NYVzxwAokFKgrc0w==", "dev": true, "optional": true }, "@nomicfoundation/solidity-analyzer-darwin-x64": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.0.tgz", - "integrity": "sha512-dlHeIg0pTL4dB1l9JDwbi/JG6dHQaU1xpDK+ugYO8eJ1kxx9Dh2isEUtA4d02cQAl22cjOHTvifAk96A+ItEHA==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.1.tgz", + "integrity": "sha512-XhQG4BaJE6cIbjAVtzGOGbK3sn1BO9W29uhk9J8y8fZF1DYz0Doj8QDMfpMu+A6TjPDs61lbsmeYodIDnfveSA==", "dev": true, "optional": true }, "@nomicfoundation/solidity-analyzer-freebsd-x64": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-freebsd-x64/-/solidity-analyzer-freebsd-x64-0.1.0.tgz", - "integrity": "sha512-WFCZYMv86WowDA4GiJKnebMQRt3kCcFqHeIomW6NMyqiKqhK1kIZCxSLDYsxqlx396kKLPN1713Q1S8tu68GKg==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-freebsd-x64/-/solidity-analyzer-freebsd-x64-0.1.1.tgz", + "integrity": "sha512-GHF1VKRdHW3G8CndkwdaeLkVBi5A9u2jwtlS7SLhBc8b5U/GcoL39Q+1CSO3hYqePNP+eV5YI7Zgm0ea6kMHoA==", "dev": true, "optional": true }, "@nomicfoundation/solidity-analyzer-linux-arm64-gnu": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.0.tgz", - "integrity": "sha512-DTw6MNQWWlCgc71Pq7CEhEqkb7fZnS7oly13pujs4cMH1sR0JzNk90Mp1zpSCsCs4oKan2ClhMlLKtNat/XRKQ==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.1.tgz", + "integrity": "sha512-g4Cv2fO37ZsUENQ2vwPnZc2zRenHyAxHcyBjKcjaSmmkKrFr64yvzeNO8S3GBFCo90rfochLs99wFVGT/0owpg==", "dev": true, "optional": true }, "@nomicfoundation/solidity-analyzer-linux-arm64-musl": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.0.tgz", - "integrity": "sha512-wUpUnR/3GV5Da88MhrxXh/lhb9kxh9V3Jya2NpBEhKDIRCDmtXMSqPMXHZmOR9DfCwCvG6vLFPr/+YrPCnUN0w==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.1.tgz", + "integrity": "sha512-WJ3CE5Oek25OGE3WwzK7oaopY8xMw9Lhb0mlYuJl/maZVo+WtP36XoQTb7bW/i8aAdHW5Z+BqrHMux23pvxG3w==", "dev": true, "optional": true }, "@nomicfoundation/solidity-analyzer-linux-x64-gnu": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.0.tgz", - "integrity": "sha512-lR0AxK1x/MeKQ/3Pt923kPvwigmGX3OxeU5qNtQ9pj9iucgk4PzhbS3ruUeSpYhUxG50jN4RkIGwUMoev5lguw==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.1.tgz", + "integrity": "sha512-5WN7leSr5fkUBBjE4f3wKENUy9HQStu7HmWqbtknfXkkil+eNWiBV275IOlpXku7v3uLsXTOKpnnGHJYI2qsdA==", "dev": true, "optional": true }, "@nomicfoundation/solidity-analyzer-linux-x64-musl": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.0.tgz", - "integrity": "sha512-A1he/8gy/JeBD3FKvmI6WUJrGrI5uWJNr5Xb9WdV+DK0F8msuOqpEByLlnTdLkXMwW7nSl3awvLezOs9xBHJEg==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.1.tgz", + "integrity": "sha512-KdYMkJOq0SYPQMmErv/63CwGwMm5XHenEna9X9aB8mQmhDBrYrlAOSsIPgFCUSL0hjxE3xHP65/EPXR/InD2+w==", "dev": true, "optional": true }, "@nomicfoundation/solidity-analyzer-win32-arm64-msvc": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-arm64-msvc/-/solidity-analyzer-win32-arm64-msvc-0.1.0.tgz", - "integrity": "sha512-7x5SXZ9R9H4SluJZZP8XPN+ju7Mx+XeUMWZw7ZAqkdhP5mK19I4vz3x0zIWygmfE8RT7uQ5xMap0/9NPsO+ykw==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-arm64-msvc/-/solidity-analyzer-win32-arm64-msvc-0.1.1.tgz", + "integrity": "sha512-VFZASBfl4qiBYwW5xeY20exWhmv6ww9sWu/krWSesv3q5hA0o1JuzmPHR4LPN6SUZj5vcqci0O6JOL8BPw+APg==", "dev": true, "optional": true }, "@nomicfoundation/solidity-analyzer-win32-ia32-msvc": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-ia32-msvc/-/solidity-analyzer-win32-ia32-msvc-0.1.0.tgz", - "integrity": "sha512-m7w3xf+hnE774YRXu+2mGV7RiF3QJtUoiYU61FascCkQhX3QMQavh7saH/vzb2jN5D24nT/jwvaHYX/MAM9zUw==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-ia32-msvc/-/solidity-analyzer-win32-ia32-msvc-0.1.1.tgz", + "integrity": "sha512-JnFkYuyCSA70j6Si6cS1A9Gh1aHTEb8kOTBApp/c7NRTFGNMH8eaInKlyuuiIbvYFhlXW4LicqyYuWNNq9hkpQ==", "dev": true, "optional": true }, "@nomicfoundation/solidity-analyzer-win32-x64-msvc": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.0.tgz", - "integrity": "sha512-xCuybjY0sLJQnJhupiFAXaek2EqF0AP0eBjgzaalPXSNvCEN6ZYHvUzdA50ENDVeSYFXcUsYf3+FsD3XKaeptA==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.1.tgz", + "integrity": "sha512-HrVJr6+WjIXGnw3Q9u6KQcbZCtk0caVWhCdFADySvRyUxJ8PnzlaP+MhwNE8oyT8OZ6ejHBRrrgjSqDCFXGirw==", "dev": true, "optional": true }, @@ -16694,9 +16774,9 @@ } }, "@openzeppelin/upgrades-core": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades-core/-/upgrades-core-1.24.0.tgz", - "integrity": "sha512-lXf1tUrCZ3Q/YmWhw0cuSSOHMp0OAsmeOg1fhSGEM6nQQ6cIVlFvq2pCV5hZMb7xkOm5pmmzV8JW1W3kfW6Lfw==", + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades-core/-/upgrades-core-1.24.1.tgz", + "integrity": "sha512-QhdIQDUykJ3vQauB6CheV7vk4zgn0e1iY+IDg7r1KqpA1m2bqIGjQCpzidW33K4bZc9zdJSPx2/Z6Um5KxCB7A==", "dev": true, "requires": { "cbor": "^8.0.0", @@ -16892,9 +16972,9 @@ } }, "@truffle/abi-utils": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/@truffle/abi-utils/-/abi-utils-0.3.8.tgz", - "integrity": "sha512-RevMtlEuQw9cE2VWzQuvLDSYPCVSZQQUOsaK8ArcwxXct6ugiJCDC7tNouhHzP1Y4ccdZtG2y/XPHQJdzgYdZQ==", + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@truffle/abi-utils/-/abi-utils-0.3.9.tgz", + "integrity": "sha512-G5dqgwRHx5zwlXjz3QT8OJVfB2cOqWwD6DwKso0KttUt/zejhCjnkKq72rSgyeLMkz7wBB9ERLOsupLBILM8MA==", "dev": true, "requires": { "change-case": "3.0.2", @@ -16909,13 +16989,13 @@ "dev": true }, "@truffle/codec": { - "version": "0.14.15", - "resolved": "https://registry.npmjs.org/@truffle/codec/-/codec-0.14.15.tgz", - "integrity": "sha512-cooWy8blmvYQQRBKgzWJnDUS6mZE9cvnmpVN15jU6TseAQkBtmfYfCH12QCKEWMq2+R4yQICP54WNCYg78g72g==", + "version": "0.14.16", + "resolved": "https://registry.npmjs.org/@truffle/codec/-/codec-0.14.16.tgz", + "integrity": "sha512-a9UY3n/FnkKN3Q4zOuMFOOcLWb80mdknj+voim4vvXYtJm1aAZQZE5sG9aLnMBTl4TiGLzUtfNDVYY7WgWgDag==", "dev": true, "requires": { - "@truffle/abi-utils": "^0.3.8", - "@truffle/compile-common": "^0.9.3", + "@truffle/abi-utils": "^0.3.9", + "@truffle/compile-common": "^0.9.4", "big.js": "^6.0.3", "bn.js": "^5.1.3", "cbor": "^5.2.0", @@ -16981,9 +17061,9 @@ } }, "@truffle/compile-common": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/@truffle/compile-common/-/compile-common-0.9.3.tgz", - "integrity": "sha512-9S86H5DRC0zEj164KeClP/6jVt1M/nRd7St89h6QbuIU0JjpqSz1SXpkvqhbFoV9hhW+4ZGh0NysjrdPlk7gFw==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/@truffle/compile-common/-/compile-common-0.9.4.tgz", + "integrity": "sha512-mnqJB/hLiPHNf+WKwt/2MH6lv34xSG/SFCib7+ckAklutUqVLeFo8EwQxinuHNkU7LY0C+YgZXhK1WTCO5YRJQ==", "dev": true, "requires": { "@truffle/error": "^0.2.0", @@ -16999,17 +17079,17 @@ } }, "@truffle/contract": { - "version": "4.6.15", - "resolved": "https://registry.npmjs.org/@truffle/contract/-/contract-4.6.15.tgz", - "integrity": "sha512-3V+50z94XRh+I3axz6Zrot1wlMhRiG2O9XjR20LwR5YBnzHV7YFfOs8x6pluXVLQyxcVJBISJyqxvGxpkecrZg==", + "version": "4.6.17", + "resolved": "https://registry.npmjs.org/@truffle/contract/-/contract-4.6.17.tgz", + "integrity": "sha512-sIMam5Wqr9AEiqHfOcWGJGqTv8Qy+BT765PaNHUUT6JBAY+tpHM3FlQd2nM6zLJ8paR3SLDGIthkhCBH/KNgDA==", "dev": true, "requires": { "@ensdomains/ensjs": "^2.1.0", "@truffle/blockchain-utils": "^0.1.6", - "@truffle/contract-schema": "^3.4.12", - "@truffle/debug-utils": "^6.0.46", + "@truffle/contract-schema": "^3.4.13", + "@truffle/debug-utils": "^6.0.47", "@truffle/error": "^0.2.0", - "@truffle/interface-adapter": "^0.5.29", + "@truffle/interface-adapter": "^0.5.30", "bignumber.js": "^7.2.1", "debug": "^4.3.1", "ethers": "^4.0.32", @@ -17029,9 +17109,9 @@ } }, "@truffle/contract-schema": { - "version": "3.4.12", - "resolved": "https://registry.npmjs.org/@truffle/contract-schema/-/contract-schema-3.4.12.tgz", - "integrity": "sha512-XpMMps/bqHwiRuCyLiEEGWEAvGGzGj4u1X1+lzxrtIsrwbQhSZcdgEbXl9vGxOOJWOup3HXRCIsjlao27kS4OA==", + "version": "3.4.13", + "resolved": "https://registry.npmjs.org/@truffle/contract-schema/-/contract-schema-3.4.13.tgz", + "integrity": "sha512-emG7upuryYFrsPDbHqeASPWXL824M1tinhQwSPG0phSoa3g+RX9fUNNN/VPmF3tSkXLWUMhRnb7ehxnaCuRbZg==", "dev": true, "requires": { "ajv": "^6.10.0", @@ -17039,12 +17119,12 @@ } }, "@truffle/debug-utils": { - "version": "6.0.46", - "resolved": "https://registry.npmjs.org/@truffle/debug-utils/-/debug-utils-6.0.46.tgz", - "integrity": "sha512-MWko3c1M0NI8IT0yNh8Dh2xoDgR2R1apP8hc/9VsR/4Q7P6OE/578WRpZnvo2HWXYBiJ2PrWBDtMYBHntImrrA==", + "version": "6.0.47", + "resolved": "https://registry.npmjs.org/@truffle/debug-utils/-/debug-utils-6.0.47.tgz", + "integrity": "sha512-bUjdzLPdEKtoUCDzaXkrOoi+PbyAJlMBzGequBK8tirT7xL9bCP2Pd/WxvnmRd7AnfroxGNvXwVXWTItW5SMWQ==", "dev": true, "requires": { - "@truffle/codec": "^0.14.15", + "@truffle/codec": "^0.14.16", "@trufflesuite/chromafi": "^3.0.0", "bn.js": "^5.1.3", "chalk": "^2.4.2", @@ -17067,9 +17147,9 @@ "dev": true }, "@truffle/interface-adapter": { - "version": "0.5.29", - "resolved": "https://registry.npmjs.org/@truffle/interface-adapter/-/interface-adapter-0.5.29.tgz", - "integrity": "sha512-6UlJ+f87z7y/dWk9UfbIU+4e80iRsp8h03LEiE5B+PvZbr6cuMjLJUBtBBQZMo3+xrIcS/2u3p5hOxW8OJm8tw==", + "version": "0.5.30", + "resolved": "https://registry.npmjs.org/@truffle/interface-adapter/-/interface-adapter-0.5.30.tgz", + "integrity": "sha512-wyCcESeZJBkAfuSGU8GHCusIWDUDyQjJZMcyShv59ZTSAwQR7xx0+a0Q1LlS532G/pGFLYe2VzKSY1pRHRwgug==", "dev": true, "requires": { "bn.js": "^5.1.3", @@ -17468,6 +17548,16 @@ "sprintf-js": "~1.0.2" } }, + "array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + } + }, "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -17748,6 +17838,15 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true + }, + "qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } } } }, @@ -18445,9 +18544,9 @@ } }, "cosmiconfig": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.0.0.tgz", - "integrity": "sha512-da1EafcpH6b/TD8vDRaWV7xFINlHlF6zKsGwS1TsuVJTZRkquaS5HTMq7uq6h31619QjbsYl21gVDOm32KM1vQ==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.1.0.tgz", + "integrity": "sha512-0tLZ9URlPGU7JsKq0DQOQ3FoRsYX8xDZ7xMiATQfaiGMz7EHowNkbU9u1coAOmnh9p/1ySpm0RB3JNWRXM5GCg==", "dev": true, "requires": { "import-fresh": "^3.2.1", @@ -18948,18 +19047,18 @@ } }, "es-abstract": { - "version": "1.21.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.1.tgz", - "integrity": "sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==", + "version": "1.21.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz", + "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==", "dev": true, "requires": { + "array-buffer-byte-length": "^1.0.0", "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", "es-set-tostringtag": "^2.0.1", "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.3", + "get-intrinsic": "^1.2.0", "get-symbol-description": "^1.0.0", "globalthis": "^1.0.3", "gopd": "^1.0.1", @@ -18967,8 +19066,8 @@ "has-property-descriptors": "^1.0.0", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", - "internal-slot": "^1.0.4", - "is-array-buffer": "^3.0.1", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", "is-callable": "^1.2.7", "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", @@ -18976,11 +19075,12 @@ "is-string": "^1.0.7", "is-typed-array": "^1.1.10", "is-weakref": "^1.0.2", - "object-inspect": "^1.12.2", + "object-inspect": "^1.12.3", "object-keys": "^1.1.1", "object.assign": "^4.1.4", "regexp.prototype.flags": "^1.4.3", "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.7", "string.prototype.trimend": "^1.0.6", "string.prototype.trimstart": "^1.0.6", "typed-array-length": "^1.0.4", @@ -19148,12 +19248,15 @@ } }, "eslint": { - "version": "8.34.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.34.0.tgz", - "integrity": "sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==", + "version": "8.36.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.36.0.tgz", + "integrity": "sha512-Y956lmS7vDqomxlaaQAHVmeb4tNMp2FWIvU/RnU5BD3IKMD/MJPr76xdyr68P8tV1iNMvN2mRK0yy3c+UjL+bw==", "dev": true, "requires": { - "@eslint/eslintrc": "^1.4.1", + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "@eslint/eslintrc": "^2.0.1", + "@eslint/js": "8.36.0", "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -19164,10 +19267,9 @@ "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", + "espree": "^9.5.0", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", @@ -19188,7 +19290,6 @@ "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.1", - "regexpp": "^3.2.0", "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" @@ -19319,9 +19420,9 @@ } }, "eslint-config-prettier": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.6.0.tgz", - "integrity": "sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.7.0.tgz", + "integrity": "sha512-HHVXLSlVUhMSmyW4ZzEuvjpwqamgmlfkutD53cYXLikh4pt/modINRcCIApJ84czDxM4GZInwUrromsDdTImTA==", "dev": true, "requires": {} }, @@ -19335,23 +19436,6 @@ "estraverse": "^5.2.0" } }, - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^2.0.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - } - } - }, "eslint-visitor-keys": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", @@ -19359,9 +19443,9 @@ "dev": true }, "espree": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", - "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.0.tgz", + "integrity": "sha512-JPbJGhKc47++oo4JkEoTe2wjy4fmMwvFpgJT9cQzmfXKp22Dr6Hf1tdCteLz1h0P3t+mGvWZ+4Uankvh8+c6zw==", "dev": true, "requires": { "acorn": "^8.8.0", @@ -19376,9 +19460,9 @@ "dev": true }, "esquery": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.2.tgz", - "integrity": "sha512-JVSoLdTlTDkmjFmab7H/9SL9qGSyjElT3myyKp7krqjVFQCDLmj1QFaCLRFBszBKI0XVZaiiXvuPIX3ZwHe1Ng==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, "requires": { "estraverse": "^5.1.0" @@ -20204,6 +20288,15 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, + "qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } + }, "raw-body": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", @@ -20816,9 +20909,9 @@ "dev": true }, "hardhat": { - "version": "2.12.7", - "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.12.7.tgz", - "integrity": "sha512-voWoN6zn5d8BOEaczSyK/1PyfdeOeI3SbGCFb36yCHTJUt6OIqLb+ZDX30VhA1UsYKzLqG7UnWl3fKJUuANc6A==", + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.13.0.tgz", + "integrity": "sha512-ZlzBOLML1QGlm6JWyVAG8lVTEAoOaVm1in/RU2zoGAnYEoD1Rp4T+ZMvrLNhHaaeS9hfjJ1gJUBfiDr4cx+htQ==", "dev": true, "requires": { "@ethersproject/abi": "^5.1.2", @@ -21347,9 +21440,9 @@ "dev": true }, "immutable": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.2.4.tgz", - "integrity": "sha512-WDxL3Hheb1JkRN3sQkyujNlL/xRjAo3rJtaU5xeufUauG66JdMr32bLj4gF+vWl84DIA3Zxw7tiAjneYzRRw+w==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz", + "integrity": "sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg==", "dev": true }, "import-fresh": { @@ -21453,13 +21546,13 @@ } }, "is-array-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.1.tgz", - "integrity": "sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", "dev": true, "requires": { "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", + "get-intrinsic": "^1.2.0", "is-typed-array": "^1.1.10" } }, @@ -23337,20 +23430,20 @@ "dev": true }, "prettier-plugin-solidity": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.1.2.tgz", - "integrity": "sha512-KC5oNbFJfyBaFiO0kl56J6AXnDmr9tUlBV1iqo864x4KQrKYKaBZvW9jhT2oC0NHoNp7/GoMJNxqL8pp8k7C/g==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.1.3.tgz", + "integrity": "sha512-fQ9yucPi2sBbA2U2Xjh6m4isUTJ7S7QLc/XDDsktqqxYfTwdYKJ0EnnywXHwCGAaYbQNK+HIYPL1OemxuMsgeg==", "dev": true, "requires": { - "@solidity-parser/parser": "^0.15.0", + "@solidity-parser/parser": "^0.16.0", "semver": "^7.3.8", "solidity-comments-extractor": "^0.0.7" }, "dependencies": { "@solidity-parser/parser": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.15.0.tgz", - "integrity": "sha512-5UFJJTzWi1hgFk6aGCZ5rxG2DJkCJOzJ74qg7UkWSNCDSigW+CJLoYUb5bLiKrtI34Nr9rpFSUNHfkqtlL+N/w==", + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.16.0.tgz", + "integrity": "sha512-ESipEcHyRHg4Np4SqBCfcXwyxxna1DgFVz69bgpLV8vzl/NP1DtcKsJ4dJZXWQhY/Z4J2LeKBiOkOVZn9ct33Q==", "dev": true, "requires": { "antlr4ts": "^0.5.0-alpha.4" @@ -23435,9 +23528,9 @@ "dev": true }, "qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.1.tgz", + "integrity": "sha512-0wsrzgTz/kAVIeuxSjnpGC56rzYtr6JT/2BwEvMaPhFIoYa1aGO8LbzuU1R0uUYQkLpWBTOj0l/CLAJB64J6nQ==", "dev": true, "requires": { "side-channel": "^1.0.4" @@ -23545,9 +23638,9 @@ } }, "readable-stream": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.1.tgz", - "integrity": "sha512-+rQmrWMYGA90yenhTYsLWAsLsqVC8osOw6PKE1HDYiO0gdPeKe/xDHNzIAIn4C91YQ6oenEhfYqqc1883qHbjQ==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, "requires": { "inherits": "^2.0.3", @@ -23620,12 +23713,6 @@ "functions-have-names": "^1.2.2" } }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true - }, "req-cwd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/req-cwd/-/req-cwd-2.0.0.tgz", @@ -24670,12 +24757,12 @@ } }, "solhint": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/solhint/-/solhint-3.4.0.tgz", - "integrity": "sha512-FYEs/LoTxMsWFP/OGsEqR1CBDn3Bn7hrTWsgtjai17MzxITgearIdlo374KKZjjIycu8E2xBcJ+RSWeoBvQmkw==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/solhint/-/solhint-3.4.1.tgz", + "integrity": "sha512-pzZn2RlZhws1XwvLPVSsxfHrwsteFf5eySOhpAytzXwKQYbTCJV6z8EevYDiSVKMpWrvbKpEtJ055CuEmzp4Xg==", "dev": true, "requires": { - "@solidity-parser/parser": "^0.15.0", + "@solidity-parser/parser": "^0.16.0", "ajv": "^6.12.6", "antlr4": "^4.11.0", "ast-parents": "^0.0.1", @@ -24696,9 +24783,9 @@ }, "dependencies": { "@solidity-parser/parser": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.15.0.tgz", - "integrity": "sha512-5UFJJTzWi1hgFk6aGCZ5rxG2DJkCJOzJ74qg7UkWSNCDSigW+CJLoYUb5bLiKrtI34Nr9rpFSUNHfkqtlL+N/w==", + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.16.0.tgz", + "integrity": "sha512-ESipEcHyRHg4Np4SqBCfcXwyxxna1DgFVz69bgpLV8vzl/NP1DtcKsJ4dJZXWQhY/Z4J2LeKBiOkOVZn9ct33Q==", "dev": true, "requires": { "antlr4ts": "^0.5.0-alpha.4" @@ -25300,9 +25387,9 @@ } }, "solidity-docgen": { - "version": "0.6.0-beta.34", - "resolved": "https://registry.npmjs.org/solidity-docgen/-/solidity-docgen-0.6.0-beta.34.tgz", - "integrity": "sha512-igdGrkg8gT1jn+B2NwzjEtSf+7NTrSi/jz88zO7MZWgETmcWbXaxgAsQP4BQeC4YFeH0Pie1NsLP7+9qDgvFtA==", + "version": "0.6.0-beta.35", + "resolved": "https://registry.npmjs.org/solidity-docgen/-/solidity-docgen-0.6.0-beta.35.tgz", + "integrity": "sha512-9QdwK1THk/MWIdq1PEW/6dvtND0pUqpFTsbKwwU9YQIMYuRhH1lek9SsgnsGGYtdJ0VTrXXcVT30q20a8Y610A==", "dev": true, "requires": { "handlebars": "^4.7.7", @@ -25401,9 +25488,9 @@ } }, "spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", @@ -25427,9 +25514,9 @@ } }, "spdx-license-ids": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", - "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", + "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==", "dev": true }, "sprintf-js": { @@ -25532,6 +25619,17 @@ "strip-ansi": "^4.0.0" } }, + "string.prototype.trim": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", + "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, "string.prototype.trimend": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", @@ -26139,9 +26237,9 @@ "dev": true }, "undici": { - "version": "5.20.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.20.0.tgz", - "integrity": "sha512-J3j60dYzuo6Eevbawwp1sdg16k5Tf768bxYK4TUJRH7cBM4kFCbf3mOnM/0E3vQYXvpxITbbWmBafaDbxLDz3g==", + "version": "5.21.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.21.0.tgz", + "integrity": "sha512-HOjK8l6a57b2ZGXOcUsI5NLfoTrfmbOl90ixJDl0AEFG4wgHNDQxtZy15/ZQp7HhjkpaGlp/eneMgtsu1dIlUA==", "dev": true, "requires": { "busboy": "^1.6.0" From 75ef7b8b27cf8d5ad8874d23754b0ff0dc256794 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Tue, 14 Mar 2023 14:27:37 +0100 Subject: [PATCH 082/133] Add FV specs for TimelockController (#4098) Co-authored-by: Francisco --- .../harnesses/TimelockControllerHarness.sol | 12 + certora/specs.json | 6 + certora/specs/AccessControl.spec | 9 +- certora/specs/TimelockController.spec | 275 ++++++++++++++++++ certora/specs/methods/IAccessControl.spec | 7 + 5 files changed, 301 insertions(+), 8 deletions(-) create mode 100644 certora/harnesses/TimelockControllerHarness.sol create mode 100644 certora/specs/TimelockController.spec create mode 100644 certora/specs/methods/IAccessControl.spec diff --git a/certora/harnesses/TimelockControllerHarness.sol b/certora/harnesses/TimelockControllerHarness.sol new file mode 100644 index 000000000..d1ea99065 --- /dev/null +++ b/certora/harnesses/TimelockControllerHarness.sol @@ -0,0 +1,12 @@ +pragma solidity ^0.8.0; + +import "../patched/governance/TimelockController.sol"; + +contract TimelockControllerHarness is TimelockController { + constructor( + uint256 minDelay, + address[] memory proposers, + address[] memory executors, + address admin + ) TimelockController(minDelay, proposers, executors, admin) {} +} diff --git a/certora/specs.json b/certora/specs.json index 228e85fe4..e76db3084 100644 --- a/certora/specs.json +++ b/certora/specs.json @@ -45,5 +45,11 @@ "spec": "Initializable", "contract": "InitializableHarness", "files": ["certora/harnesses/InitializableHarness.sol"] + }, + { + "spec": "TimelockController", + "contract": "TimelockControllerHarness", + "files": ["certora/harnesses/TimelockControllerHarness.sol"], + "options": ["--optimistic_hashing", "--optimistic_loop"] } ] diff --git a/certora/specs/AccessControl.spec b/certora/specs/AccessControl.spec index 8e8f6ac9d..35927c5d3 100644 --- a/certora/specs/AccessControl.spec +++ b/certora/specs/AccessControl.spec @@ -1,12 +1,5 @@ import "helpers.spec" - -methods { - hasRole(bytes32, address) returns(bool) envfree - getRoleAdmin(bytes32) returns(bytes32) envfree - grantRole(bytes32, address) - revokeRole(bytes32, address) - renounceRole(bytes32, address) -} +import "methods/IAccessControl.spec" /* ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ diff --git a/certora/specs/TimelockController.spec b/certora/specs/TimelockController.spec new file mode 100644 index 000000000..e140c11de --- /dev/null +++ b/certora/specs/TimelockController.spec @@ -0,0 +1,275 @@ +import "helpers.spec" +import "methods/IAccessControl.spec" + +methods { + TIMELOCK_ADMIN_ROLE() returns (bytes32) envfree + PROPOSER_ROLE() returns (bytes32) envfree + EXECUTOR_ROLE() returns (bytes32) envfree + CANCELLER_ROLE() returns (bytes32) envfree + isOperation(bytes32) returns (bool) envfree + isOperationPending(bytes32) returns (bool) envfree + isOperationReady(bytes32) returns (bool) + isOperationDone(bytes32) returns (bool) envfree + getTimestamp(bytes32) returns (uint256) envfree + getMinDelay() returns (uint256) envfree + + hashOperation(address, uint256, bytes, bytes32, bytes32) returns(bytes32) envfree + hashOperationBatch(address[], uint256[], bytes[], bytes32, bytes32) returns(bytes32) envfree + + schedule(address, uint256, bytes, bytes32, bytes32, uint256) + scheduleBatch(address[], uint256[], bytes[], bytes32, bytes32, uint256) + execute(address, uint256, bytes, bytes32, bytes32) + executeBatch(address[], uint256[], bytes[], bytes32, bytes32) + cancel(bytes32) + + updateDelay(uint256) +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Helpers │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +// Uniformly handle scheduling of batched and non-batched operations. +function helperScheduleWithRevert(env e, method f, bytes32 id, uint256 delay) { + if (f.selector == schedule(address, uint256, bytes, bytes32, bytes32, uint256).selector) { + address target; uint256 value; bytes data; bytes32 predecessor; bytes32 salt; + require hashOperation(target, value, data, predecessor, salt) == id; // Correlation + schedule@withrevert(e, target, value, data, predecessor, salt, delay); + } else if (f.selector == scheduleBatch(address[], uint256[], bytes[], bytes32, bytes32, uint256).selector) { + address[] targets; uint256[] values; bytes[] payloads; bytes32 predecessor; bytes32 salt; + require hashOperationBatch(targets, values, payloads, predecessor, salt) == id; // Correlation + scheduleBatch@withrevert(e, targets, values, payloads, predecessor, salt, delay); + } else { + calldataarg args; + f@withrevert(e, args); + } +} + +// Uniformly handle execution of batched and non-batched operations. +function helperExecuteWithRevert(env e, method f, bytes32 id, bytes32 predecessor) { + if (f.selector == execute(address, uint256, bytes, bytes32, bytes32).selector) { + address target; uint256 value; bytes data; bytes32 salt; + require hashOperation(target, value, data, predecessor, salt) == id; // Correlation + execute@withrevert(e, target, value, data, predecessor, salt); + } else if (f.selector == executeBatch(address[], uint256[], bytes[], bytes32, bytes32).selector) { + address[] targets; uint256[] values; bytes[] payloads; bytes32 salt; + require hashOperationBatch(targets, values, payloads, predecessor, salt) == id; // Correlation + executeBatch@withrevert(e, targets, values, payloads, predecessor, salt); + } else { + calldataarg args; + f@withrevert(e, args); + } +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Definitions │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +definition DONE_TIMESTAMP() returns uint256 = 1; +definition UNSET() returns uint8 = 0x1; +definition PENDING() returns uint8 = 0x2; +definition DONE() returns uint8 = 0x4; + +definition isUnset(bytes32 id) returns bool = !isOperation(id); +definition isPending(bytes32 id) returns bool = isOperationPending(id); +definition isDone(bytes32 id) returns bool = isOperationDone(id); +definition state(bytes32 id) returns uint8 = (isUnset(id) ? UNSET() : 0) | (isPending(id) ? PENDING() : 0) | (isDone(id) ? DONE() : 0); + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariants: consistency of accessors │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant isOperationCheck(bytes32 id) + isOperation(id) <=> getTimestamp(id) > 0 + filtered { f -> !f.isView } + +invariant isOperationPendingCheck(bytes32 id) + isOperationPending(id) <=> getTimestamp(id) > DONE_TIMESTAMP() + filtered { f -> !f.isView } + +invariant isOperationDoneCheck(bytes32 id) + isOperationDone(id) <=> getTimestamp(id) == DONE_TIMESTAMP() + filtered { f -> !f.isView } + +invariant isOperationReadyCheck(env e, bytes32 id) + isOperationReady(e, id) <=> (isOperationPending(id) && getTimestamp(id) <= e.block.timestamp) + filtered { f -> !f.isView } + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: a proposal id is either unset, pending or done │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant stateConsistency(bytes32 id, env e) + // Check states are mutually exclusive + (isUnset(id) <=> (!isPending(id) && !isDone(id) )) && + (isPending(id) <=> (!isUnset(id) && !isDone(id) )) && + (isDone(id) <=> (!isUnset(id) && !isPending(id))) && + // Check that the state helper behaves as expected: + (isUnset(id) <=> state(id) == UNSET() ) && + (isPending(id) <=> state(id) == PENDING() ) && + (isDone(id) <=> state(id) == DONE() ) && + // Check substate + isOperationReady(e, id) => isPending(id) + filtered { f -> !f.isView } + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: state transition rules │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule stateTransition(bytes32 id, env e, method f, calldataarg args) { + require e.block.timestamp > 1; // Sanity + + uint8 stateBefore = state(id); + f(e, args); + uint8 stateAfter = state(id); + + // Cannot jump from UNSET to DONE + assert stateBefore == UNSET() => stateAfter != DONE(); + + // UNSET → PENDING: schedule or scheduleBatch + assert stateBefore == UNSET() && stateAfter == PENDING() => ( + f.selector == schedule(address, uint256, bytes, bytes32, bytes32, uint256).selector || + f.selector == scheduleBatch(address[], uint256[], bytes[], bytes32, bytes32, uint256).selector + ); + + // PENDING → UNSET: cancel + assert stateBefore == PENDING() && stateAfter == UNSET() => ( + f.selector == cancel(bytes32).selector + ); + + // PENDING → DONE: execute or executeBatch + assert stateBefore == PENDING() && stateAfter == DONE() => ( + f.selector == execute(address, uint256, bytes, bytes32, bytes32).selector || + f.selector == executeBatch(address[], uint256[], bytes[], bytes32, bytes32).selector + ); + + // DONE is final + assert stateBefore == DONE() => stateAfter == DONE(); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: minimum delay can only be updated through a timelock execution │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule minDelayOnlyChange(env e) { + uint256 delayBefore = getMinDelay(); + + method f; calldataarg args; + f(e, args); + + assert delayBefore != getMinDelay() => (e.msg.sender == currentContract && f.selector == updateDelay(uint256).selector), "Unauthorized delay update"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: schedule liveness and effects │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule schedule(env e, method f, bytes32 id, uint256 delay) filtered { f -> + f.selector == schedule(address, uint256, bytes, bytes32, bytes32, uint256).selector || + f.selector == scheduleBatch(address[], uint256[], bytes[], bytes32, bytes32, uint256).selector +} { + require nonpayable(e); + + // Basic timestamp assumptions + require e.block.timestamp > 1; + require e.block.timestamp + delay < max_uint256; + require e.block.timestamp + getMinDelay() < max_uint256; + + bytes32 otherId; uint256 otherTimestamp = getTimestamp(otherId); + + uint8 stateBefore = state(id); + bool isDelaySufficient = delay >= getMinDelay(); + bool isProposerBefore = hasRole(PROPOSER_ROLE(), e.msg.sender); + + helperScheduleWithRevert(e, f, id, delay); + bool success = !lastReverted; + + // liveness + assert success <=> ( + stateBefore == UNSET() && + isDelaySufficient && + isProposerBefore + ); + + // effect + assert success => state(id) == PENDING(), "State transition violation"; + assert success => getTimestamp(id) == to_uint256(e.block.timestamp + delay), "Proposal timestamp not correctly set"; + + // no side effect + assert otherTimestamp != getTimestamp(otherId) => id == otherId, "Other proposal affected"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: execute liveness and effects │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule execute(env e, method f, bytes32 id, bytes32 predecessor) filtered { f -> + f.selector == execute(address, uint256, bytes, bytes32, bytes32).selector || + f.selector == executeBatch(address[], uint256[], bytes[], bytes32, bytes32).selector +} { + bytes32 otherId; uint256 otherTimestamp = getTimestamp(otherId); + + uint8 stateBefore = state(id); + bool isOperationReadyBefore = isOperationReady(e, id); + bool isExecutorOrOpen = hasRole(EXECUTOR_ROLE(), e.msg.sender) || hasRole(EXECUTOR_ROLE(), 0); + bool predecessorDependency = predecessor == 0 || isDone(predecessor); + + helperExecuteWithRevert(e, f, id, predecessor); + bool success = !lastReverted; + + // 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 + // proposal can revert for reasons beyond our control. + + // liveness, should be `<=>` but can only check `=>` (see comment above) + assert success => ( + stateBefore == PENDING() && + isOperationReadyBefore && + predecessorDependency && + isExecutorOrOpen + ); + + // effect + assert success => state(id) == DONE(), "State transition violation"; + + // no side effect + assert otherTimestamp != getTimestamp(otherId) => id == otherId, "Other proposal affected"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: cancel liveness and effects │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule cancel(env e, bytes32 id) { + require nonpayable(e); + + bytes32 otherId; uint256 otherTimestamp = getTimestamp(otherId); + + uint8 stateBefore = state(id); + bool isCanceller = hasRole(CANCELLER_ROLE(), e.msg.sender); + + cancel@withrevert(e, id); + bool success = !lastReverted; + + // liveness + assert success <=> ( + stateBefore == PENDING() && + isCanceller + ); + + // effect + assert success => state(id) == UNSET(), "State transition violation"; + + // no side effect + assert otherTimestamp != getTimestamp(otherId) => id == otherId, "Other proposal affected"; +} diff --git a/certora/specs/methods/IAccessControl.spec b/certora/specs/methods/IAccessControl.spec new file mode 100644 index 000000000..4d41ffda7 --- /dev/null +++ b/certora/specs/methods/IAccessControl.spec @@ -0,0 +1,7 @@ +methods { + hasRole(bytes32, address) returns(bool) envfree + getRoleAdmin(bytes32) returns(bytes32) envfree + grantRole(bytes32, address) + revokeRole(bytes32, address) + renounceRole(bytes32, address) +} From 1c8df659b98177b737fd8af411b30bf24c1cbef1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Garc=C3=ADa?= Date: Tue, 14 Mar 2023 15:14:01 -0700 Subject: [PATCH 083/133] Clarify Governor Bravo compatibility scope (#4090) Co-authored-by: Francisco --- docs/modules/ROOT/pages/governance.adoc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/governance.adoc b/docs/modules/ROOT/pages/governance.adoc index cd7dd4e6f..c5bcf58cd 100644 --- a/docs/modules/ROOT/pages/governance.adoc +++ b/docs/modules/ROOT/pages/governance.adoc @@ -20,7 +20,9 @@ The ERC20 extension to keep track of votes and vote delegation is one such case. === Governor & GovernorCompatibilityBravo -An OpenZeppelin Governor contract is by default not interface-compatible with GovernorAlpha or Bravo, since some of the functions are different or missing, although it shares all of the same events. However, it’s possible to opt in to full compatibility by inheriting from the GovernorCompatibilityBravo module. The contract will be cheaper to deploy and use without this module. +An OpenZeppelin Governor contract is by default not interface-compatible with Compound's GovernorAlpha or Bravo. Even though events are fully compatible, proposal lifecycle functions (creation, execution, etc.) have different signatures that are meant to optimize storage use. Other functions from GovernorAlpha are Bravo are likewise not available. It’s possible to opt in to a higher level of compatibility by inheriting from the GovernorCompatibilityBravo module, which covers the proposal lifecycle functions such as `propose` and `execute`. + +Note that even with the use of this module, there will still be differences in the way that `proposalId`s are calculated. Governor uses the hash of the proposal parameters with the purpose of keeping its data off-chain by event indexing, while the original Bravo implementation uses sequential `proposalId`s. Due to this and other differences, several of the functions from GovernorBravo are not included in the compatibility module. === GovernorTimelockControl & GovernorTimelockCompound From 4f4b6ab40315e2fbfc06e65d78f06c5b26d4646c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Garc=C3=ADa?= Date: Wed, 15 Mar 2023 08:06:25 -0600 Subject: [PATCH 084/133] Update certora/README.md (#4114) Co-authored-by: Francisco --- certora/README.md | 76 +++++++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/certora/README.md b/certora/README.md index 55f84d42f..cd85ba3d4 100644 --- a/certora/README.md +++ b/certora/README.md @@ -1,56 +1,60 @@ # Running the certora verification tool -These instructions detail the process for running CVT on the OpenZeppelin (Wizard/Governor) contracts. +These instructions detail the process for running Certora Verification Tool on OpenZeppelin Contracts. -Documentation for CVT and the specification language are available -[here](https://certora.atlassian.net/wiki/spaces/CPD/overview) +Documentation for CVT and the specification language are available [here](https://certora.atlassian.net/wiki/spaces/CPD/overview). + +## Prerequisites + +Follow the [Certora installation guide](https://docs.certora.com/en/latest/docs/user-guide/getting-started/install.html) in order to get the Certora Prover Package and the `solc` executable folder in your path. + +> **Note** +> An API Key is required for local testing. Although the prover will run on a Github Actions' CI environment on selected Pull Requests. ## Running the verification -The scripts in the `certora/scripts` directory are used to submit verification -jobs to the Certora verification service. After the job is complete, the results will be available on -[the Certora portal](https://vaas-stg.certora.com/). +The Certora Verification Tool proves specs for contracts, which are defined by the `./specs.json` file along with their pre-configured options. -These scripts should be run from the root directory; for example by running +The verification script `./run.js` is used to submit verification jobs to the Certora Verification service. -``` -sh certora/scripts/verifyAll.sh +You can run it from the root of the repository with the following command: + +```bash +node certora/run.js [[CONTRACT_NAME:]SPEC_NAME] [OPTIONS...] ``` -The most important of these is `verifyAll.sh`, which checks -all of the harnessed contracts (`certora/harness/Wizard*.sol`) against all of -the specifications (`certora/spec/*.spec`). +Where: -The other scripts run a subset of the specifications or the contracts. You can -verify different contracts or specifications by changing the `--verify` option, -and you can run a single rule or method with the `--rule` or `--method` option. +- `CONTRACT_NAME` matches the `contract` key in the `./spec.json` file and may be empty. It will run all matching contracts if not provided. +- `SPEC_NAME` refers to a `spec` key from the `./specs.json` file. It will run every spec if not provided. +- `OPTIONS` extend the [Certora Prover CLI options](https://docs.certora.com/en/latest/docs/prover/cli/options.html#certora-prover-cli-options) and will respect the preconfigured options in the `specs.json` file. -For example, to verify the `WizardFirstPriority` contract against the -`GovernorCountingSimple` specification, you could change the `--verify` line of -the `WizardControlFirstPriortity.sh` script to: +> **Note** +> A single spec may be configured to run for multiple contracts, whereas a single contract may run multiple specs. -``` ---verify WizardFirstPriority:certora/specs/GovernorCountingSimple.spec \ +Example usage: + +```bash +node certora/run.js AccessControl # Run the AccessControl spec against every contract implementing it ``` ## Adapting to changes in the contracts -Some of our rules require the code to be simplified in various ways. Our -primary tool for performing these simplifications is to run verification on a -contract that extends the original contracts and overrides some of the methods. -These "harness" contracts can be found in the `certora/harness` directory. +Some of our rules require the code to be simplified in various ways. Our primary tool for performing these simplifications is to run verification on a contract that extends the original contracts and overrides some of the methods. These "harness" contracts can be found in the `certora/harness` directory. -This pattern does require some modifications to the original code: some methods -need to be made virtual or public, for example. These changes are handled by -applying a patch to the code before verification. +This pattern does require some modifications to the original code: some methods need to be made virtual or public, for example. These changes are handled by applying a patch +to the code before verification by running: -When one of the `verify` scripts is executed, it first applies the patch file -`certora/applyHarness.patch` to the `contracts` directory, placing the output -in the `certora/munged` directory. We then verify the contracts in the -`certora/munged` directory. +```bash +make -C certora apply +``` -If the original contracts change, it is possible to create a conflict with the -patch. In this case, the verify scripts will report an error message and output -rejected changes in the `munged` directory. After merging the changes, run -`make record` in the `certora` directory; this will regenerate the patch file, -which can then be checked into git. +Before running the `certora/run.js` script, it's required to apply the corresponding patches to the `contracts` directory, placing the output in the `certora/patched` directory. Then, the contracts are verified by running the verification for the `certora/patched` directory. + +If the original contracts change, it is possible to create a conflict with the patch. In this case, the verify scripts will report an error message and output rejected changes in the `patched` directory. After merging the changes, run `make record` in the `certora` directory; this will regenerate the patch file, which can then be checked into git. + +For more information about the `make` scripts available, run: + +```bash +make -C certora help +``` From 1a60b061d5bb809c3d7e4ee915c77a00b1eca95d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Garc=C3=ADa?= Date: Thu, 16 Mar 2023 13:08:28 -0600 Subject: [PATCH 085/133] Add Pausable FV (#4117) Co-authored-by: Hadrien Croubois --- .gitignore | 1 + certora/harnesses/PausableHarness.sol | 19 ++++++ certora/specs.json | 5 ++ certora/specs/Pausable.spec | 96 +++++++++++++++++++++++++++ 4 files changed, 121 insertions(+) create mode 100644 certora/harnesses/PausableHarness.sol create mode 100644 certora/specs/Pausable.spec diff --git a/.gitignore b/.gitignore index 9350b262e..2aac74485 100644 --- a/.gitignore +++ b/.gitignore @@ -68,3 +68,4 @@ contracts-exposed .certora* .last_confs certora_* +.zip-output-url.txt diff --git a/certora/harnesses/PausableHarness.sol b/certora/harnesses/PausableHarness.sol new file mode 100644 index 000000000..37c5d591d --- /dev/null +++ b/certora/harnesses/PausableHarness.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../patched/security/Pausable.sol"; + +contract PausableHarness is Pausable { + function pause() external { + _pause(); + } + + function unpause() external { + _unpause(); + } + + function onlyWhenPaused() external whenPaused {} + + function onlyWhenNotPaused() external whenNotPaused {} +} diff --git a/certora/specs.json b/certora/specs.json index e76db3084..80fbf26af 100644 --- a/certora/specs.json +++ b/certora/specs.json @@ -1,4 +1,9 @@ [ + { + "spec": "Pausable", + "contract": "PausableHarness", + "files": ["certora/harnesses/PausableHarness.sol"] + }, { "spec": "AccessControl", "contract": "AccessControlHarness", diff --git a/certora/specs/Pausable.spec b/certora/specs/Pausable.spec new file mode 100644 index 000000000..e49293ffc --- /dev/null +++ b/certora/specs/Pausable.spec @@ -0,0 +1,96 @@ +import "helpers.spec" + +methods { + paused() returns (bool) envfree + pause() + unpause() + onlyWhenPaused() + onlyWhenNotPaused() +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: _pause pauses the contract │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule pause(env e) { + require nonpayable(e); + + bool pausedBefore = paused(); + + pause@withrevert(e); + bool success = !lastReverted; + + bool pausedAfter = paused(); + + // liveness + assert success <=> !pausedBefore, "works if and only if the contract was not paused before"; + + // effect + assert success => pausedAfter, "contract must be paused after a successful call"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: _unpause unpauses the contract │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule unpause(env e) { + require nonpayable(e); + + bool pausedBefore = paused(); + + unpause@withrevert(e); + bool success = !lastReverted; + + bool pausedAfter = paused(); + + // liveness + assert success <=> pausedBefore, "works if and only if the contract was paused before"; + + // effect + assert success => !pausedAfter, "contract must be unpaused after a successful call"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: whenPaused modifier can only be called if the contract is paused │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule whenPaused(env e) { + require nonpayable(e); + + onlyWhenPaused@withrevert(e); + assert !lastReverted <=> paused(), "works if and only if the contract is paused"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: whenNotPaused modifier can only be called if the contract is not paused │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule whenNotPaused(env e) { + require nonpayable(e); + + onlyWhenNotPaused@withrevert(e); + assert !lastReverted <=> !paused(), "works if and only if the contract is not paused"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rules: only _pause and _unpause can change paused status │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule noPauseChange(env e) { + method f; + calldataarg args; + + bool pausedBefore = paused(); + f(e, args); + bool pausedAfter = paused(); + + assert pausedBefore != pausedAfter => ( + (!pausedAfter && f.selector == unpause().selector) || + (pausedAfter && f.selector == pause().selector) + ), "contract's paused status can only be changed by _pause() or _unpause()"; +} From 3f610ebc25480bf6145e519c96e2f809996db8ed Mon Sep 17 00:00:00 2001 From: mmqxyz <127844428+mmqxyz@users.noreply.github.com> Date: Tue, 21 Mar 2023 15:33:16 +0100 Subject: [PATCH 086/133] Fix typo in README (#4129) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 094637ed6..9fc95518a 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ The engineering guidelines we follow to promote project quality can be found in Past audits can be found in [`audits/`](./audits). -Smart contracts are a nascent techology and carry a high level of technical risk and uncertainty. Although OpenZeppelin is well known for its security audits, using OpenZeppelin Contracts is not a substitute for a security audit. +Smart contracts are a nascent technology and carry a high level of technical risk and uncertainty. Although OpenZeppelin is well known for its security audits, using OpenZeppelin Contracts is not a substitute for a security audit. OpenZeppelin Contracts is made available under the MIT License, which disclaims all warranties in relation to the project and which limits the liability of those that contribute and maintain the project, including OpenZeppelin. As set out further in the Terms, you acknowledge that you are solely responsible for any use of OpenZeppelin Contracts and you assume all risks associated with any such use. From ca822213f2275a14c26167bd387ac3522da67fe9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Garc=C3=ADa?= Date: Sun, 26 Mar 2023 11:23:13 -0600 Subject: [PATCH 087/133] Make AccessControlDefaultAdminRules delay configurable (#4079) Co-authored-by: Francisco Co-authored-by: Hadrien Croubois --- .../access/AccessControlDefaultAdminRules.sol | 409 +++++++---- .../IAccessControlDefaultAdminRules.sol | 139 +++- test/access/AccessControl.behavior.js | 651 ++++++++++++++---- .../AccessControlDefaultAdminRules.test.js | 2 +- .../SupportsInterface.behavior.js | 5 +- 5 files changed, 901 insertions(+), 305 deletions(-) diff --git a/contracts/access/AccessControlDefaultAdminRules.sol b/contracts/access/AccessControlDefaultAdminRules.sol index e3bce6b75..43fca9350 100644 --- a/contracts/access/AccessControlDefaultAdminRules.sol +++ b/contracts/access/AccessControlDefaultAdminRules.sol @@ -19,9 +19,9 @@ import "../interfaces/IERC5313.sol"; * This contract implements the following risk mitigations on top of {AccessControl}: * * * Only one account holds the `DEFAULT_ADMIN_ROLE` since deployment until it's potentially renounced. - * * Enforce a 2-step process to transfer the `DEFAULT_ADMIN_ROLE` to another account. - * * Enforce a configurable delay between the two steps, with the ability to cancel in between. - * - Even after the timer has passed to avoid locking it forever. + * * Enforces a 2-step process to transfer the `DEFAULT_ADMIN_ROLE` to another account. + * * Enforces a configurable delay between the two steps, with the ability to cancel before the transfer is accepted. + * * The delay can be changed by scheduling, see {changeDefaultAdminDelay}. * * It is not possible to use another role to manage the `DEFAULT_ADMIN_ROLE`. * * Example usage: @@ -32,66 +32,31 @@ import "../interfaces/IERC5313.sol"; * 3 days, * msg.sender // Explicit initial `DEFAULT_ADMIN_ROLE` holder * ) {} - *} + * } * ``` * - * NOTE: The `delay` can only be set in the constructor and is fixed thereafter. - * * _Available since v4.9._ */ abstract contract AccessControlDefaultAdminRules is IAccessControlDefaultAdminRules, IERC5313, AccessControl { - uint48 private immutable _defaultAdminDelay; - - address private _currentDefaultAdmin; + // pending admin pair read/written together frequently address private _pendingDefaultAdmin; + uint48 private _pendingDefaultAdminSchedule; // 0 == unset - uint48 private _defaultAdminTransferDelayedUntil; + uint48 private _currentDelay; + address private _currentDefaultAdmin; + + // pending delay pair read/written together frequently + uint48 private _pendingDelay; + uint48 private _pendingDelaySchedule; // 0 == unset /** - * @dev Sets the initial values for {defaultAdminDelay} in seconds and {defaultAdmin}. - * - * The `defaultAdminDelay` value is immutable. It can only be set at the constructor. + * @dev Sets the initial values for {defaultAdminDelay} and {defaultAdmin} address. */ - constructor(uint48 defaultAdminDelay_, address initialDefaultAdmin) { - _defaultAdminDelay = defaultAdminDelay_; + constructor(uint48 initialDelay, address initialDefaultAdmin) { + _currentDelay = initialDelay; _grantRole(DEFAULT_ADMIN_ROLE, initialDefaultAdmin); } - /** - * @dev See {IERC5313-owner}. - */ - function owner() public view virtual returns (address) { - return defaultAdmin(); - } - - /** - * @inheritdoc IAccessControlDefaultAdminRules - */ - function defaultAdminDelay() public view virtual returns (uint48) { - return _defaultAdminDelay; - } - - /** - * @inheritdoc IAccessControlDefaultAdminRules - */ - function defaultAdmin() public view virtual returns (address) { - return _currentDefaultAdmin; - } - - /** - * @inheritdoc IAccessControlDefaultAdminRules - */ - function pendingDefaultAdmin() public view virtual returns (address) { - return _pendingDefaultAdmin; - } - - /** - * @inheritdoc IAccessControlDefaultAdminRules - */ - function defaultAdminTransferDelayedUntil() public view virtual returns (uint48) { - return _defaultAdminTransferDelayedUntil; - } - /** * @dev See {IERC165-supportsInterface}. */ @@ -100,50 +65,15 @@ abstract contract AccessControlDefaultAdminRules is IAccessControlDefaultAdminRu } /** - * @inheritdoc IAccessControlDefaultAdminRules + * @dev See {IERC5313-owner}. */ - function beginDefaultAdminTransfer(address newAdmin) public virtual onlyRole(DEFAULT_ADMIN_ROLE) { - _beginDefaultAdminTransfer(newAdmin); + function owner() public view virtual returns (address) { + return defaultAdmin(); } - /** - * @inheritdoc IAccessControlDefaultAdminRules - */ - function acceptDefaultAdminTransfer() public virtual { - require(_msgSender() == pendingDefaultAdmin(), "AccessControl: pending admin must accept"); - _acceptDefaultAdminTransfer(); - } - - /** - * @inheritdoc IAccessControlDefaultAdminRules - */ - function cancelDefaultAdminTransfer() public virtual onlyRole(DEFAULT_ADMIN_ROLE) { - _resetDefaultAdminTransfer(); - } - - /** - * @dev Revokes `role` from the calling account. - * - * For `DEFAULT_ADMIN_ROLE`, only allows renouncing in two steps, so it's required - * that the {defaultAdminTransferDelayedUntil} has passed and the pending default admin is the zero address. - * After its execution, it will not be possible to call `onlyRole(DEFAULT_ADMIN_ROLE)` - * functions. - * - * For other roles, see {AccessControl-renounceRole}. - * - * NOTE: Renouncing `DEFAULT_ADMIN_ROLE` will leave the contract without a defaultAdmin, - * thereby disabling any functionality that is only available to the default admin, and the - * possibility of reassigning a non-administrated role. - */ - function renounceRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) { - if (role == DEFAULT_ADMIN_ROLE) { - require( - pendingDefaultAdmin() == address(0) && _hasDefaultAdminTransferDelayPassed(), - "AccessControl: only can renounce in two delayed steps" - ); - } - super.renounceRole(role, account); - } + /// + /// Override AccessControl role management + /// /** * @dev See {AccessControl-grantRole}. Reverts for `DEFAULT_ADMIN_ROLE`. @@ -162,24 +92,37 @@ abstract contract AccessControlDefaultAdminRules is IAccessControlDefaultAdminRu } /** - * @dev See {AccessControl-_setRoleAdmin}. Reverts for `DEFAULT_ADMIN_ROLE`. + * @dev See {AccessControl-renounceRole}. + * + * For the `DEFAULT_ADMIN_ROLE`, it only allows renouncing in two steps by first calling + * {beginDefaultAdminTransfer} to the `address(0)`, so it's required that the {pendingDefaultAdmin} schedule + * has also passed when calling this function. + * + * After its execution, it will not be possible to call `onlyRole(DEFAULT_ADMIN_ROLE)` functions. + * + * NOTE: Renouncing `DEFAULT_ADMIN_ROLE` will leave the contract without a {defaultAdmin}, + * thereby disabling any functionality that is only available for it, and the possibility of reassigning a + * non-administrated role. */ - function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual override { - require(role != DEFAULT_ADMIN_ROLE, "AccessControl: can't violate default admin rules"); - super._setRoleAdmin(role, adminRole); + function renounceRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) { + if (role == DEFAULT_ADMIN_ROLE) { + (address newDefaultAdmin, uint48 schedule) = pendingDefaultAdmin(); + require( + newDefaultAdmin == address(0) && _isScheduleSet(schedule) && _hasSchedulePassed(schedule), + "AccessControl: only can renounce in two delayed steps" + ); + } + super.renounceRole(role, account); } /** - * @dev Grants `role` to `account`. + * @dev See {AccessControl-_grantRole}. * - * For `DEFAULT_ADMIN_ROLE`, it only allows granting if there isn't already a role's holder - * or if the role has been previously renounced. + * For `DEFAULT_ADMIN_ROLE`, it only allows granting if there isn't already a {defaultAdmin} or if the + * role has been previously renounced. * - * For other roles, see {AccessControl-renounceRole}. - * - * NOTE: Exposing this function through another mechanism may make the - * `DEFAULT_ADMIN_ROLE` assignable again. Make sure to guarantee this is - * the expected behavior in your implementation. + * NOTE: Exposing this function through another mechanism may make the `DEFAULT_ADMIN_ROLE` + * assignable again. Make sure to guarantee this is the expected behavior in your implementation. */ function _grantRole(bytes32 role, address account) internal virtual override { if (role == DEFAULT_ADMIN_ROLE) { @@ -189,29 +132,6 @@ abstract contract AccessControlDefaultAdminRules is IAccessControlDefaultAdminRu super._grantRole(role, account); } - /** - * @dev See {acceptDefaultAdminTransfer}. - * - * Internal function without access restriction. - */ - function _acceptDefaultAdminTransfer() internal virtual { - require(_hasDefaultAdminTransferDelayPassed(), "AccessControl: transfer delay not passed"); - _revokeRole(DEFAULT_ADMIN_ROLE, defaultAdmin()); - _grantRole(DEFAULT_ADMIN_ROLE, pendingDefaultAdmin()); - _resetDefaultAdminTransfer(); - } - - /** - * @dev See {beginDefaultAdminTransfer}. - * - * Internal function without access restriction. - */ - function _beginDefaultAdminTransfer(address newAdmin) internal virtual { - _defaultAdminTransferDelayedUntil = SafeCast.toUint48(block.timestamp) + defaultAdminDelay(); - _pendingDefaultAdmin = newAdmin; - emit DefaultAdminRoleChangeStarted(pendingDefaultAdmin(), defaultAdminTransferDelayedUntil()); - } - /** * @dev See {AccessControl-_revokeRole}. */ @@ -223,18 +143,239 @@ abstract contract AccessControlDefaultAdminRules is IAccessControlDefaultAdminRu } /** - * @dev Resets the pending default admin and delayed until. + * @dev See {AccessControl-_setRoleAdmin}. Reverts for `DEFAULT_ADMIN_ROLE`. */ - function _resetDefaultAdminTransfer() private { - delete _pendingDefaultAdmin; - delete _defaultAdminTransferDelayedUntil; + function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual override { + require(role != DEFAULT_ADMIN_ROLE, "AccessControl: can't violate default admin rules"); + super._setRoleAdmin(role, adminRole); + } + + /// + /// AccessControlDefaultAdminRules accessors + /// + + /** + * @inheritdoc IAccessControlDefaultAdminRules + */ + function defaultAdmin() public view virtual returns (address) { + return _currentDefaultAdmin; } /** - * @dev Checks if a {defaultAdminTransferDelayedUntil} has been set and passed. + * @inheritdoc IAccessControlDefaultAdminRules */ - function _hasDefaultAdminTransferDelayPassed() private view returns (bool) { - uint48 delayedUntil = defaultAdminTransferDelayedUntil(); - return delayedUntil > 0 && delayedUntil < block.timestamp; + function pendingDefaultAdmin() public view virtual returns (address newAdmin, uint48 schedule) { + return (_pendingDefaultAdmin, _pendingDefaultAdminSchedule); + } + + /** + * @inheritdoc IAccessControlDefaultAdminRules + */ + function defaultAdminDelay() public view virtual returns (uint48) { + uint48 schedule = _pendingDelaySchedule; + return (_isScheduleSet(schedule) && _hasSchedulePassed(schedule)) ? _pendingDelay : _currentDelay; + } + + /** + * @inheritdoc IAccessControlDefaultAdminRules + */ + function pendingDefaultAdminDelay() public view virtual returns (uint48 newDelay, uint48 schedule) { + schedule = _pendingDelaySchedule; + return (_isScheduleSet(schedule) && !_hasSchedulePassed(schedule)) ? (_pendingDelay, schedule) : (0, 0); + } + + /** + * @inheritdoc IAccessControlDefaultAdminRules + */ + function defaultAdminDelayIncreaseWait() public view virtual returns (uint48) { + return 5 days; + } + + /// + /// AccessControlDefaultAdminRules public and internal setters for defaultAdmin/pendingDefaultAdmin + /// + + /** + * @inheritdoc IAccessControlDefaultAdminRules + */ + function beginDefaultAdminTransfer(address newAdmin) public virtual onlyRole(DEFAULT_ADMIN_ROLE) { + _beginDefaultAdminTransfer(newAdmin); + } + + /** + * @dev See {beginDefaultAdminTransfer}. + * + * Internal function without access restriction. + */ + function _beginDefaultAdminTransfer(address newAdmin) internal virtual { + uint48 newSchedule = SafeCast.toUint48(block.timestamp) + defaultAdminDelay(); + _setPendingDefaultAdmin(newAdmin, newSchedule); + emit DefaultAdminTransferScheduled(newAdmin, newSchedule); + } + + /** + * @inheritdoc IAccessControlDefaultAdminRules + */ + function cancelDefaultAdminTransfer() public virtual onlyRole(DEFAULT_ADMIN_ROLE) { + _cancelDefaultAdminTransfer(); + } + + /** + * @dev See {cancelDefaultAdminTransfer}. + * + * Internal function without access restriction. + */ + function _cancelDefaultAdminTransfer() internal virtual { + _setPendingDefaultAdmin(address(0), 0); + } + + /** + * @inheritdoc IAccessControlDefaultAdminRules + */ + function acceptDefaultAdminTransfer() public virtual { + (address newDefaultAdmin, ) = pendingDefaultAdmin(); + require(_msgSender() == newDefaultAdmin, "AccessControl: pending admin must accept"); + _acceptDefaultAdminTransfer(); + } + + /** + * @dev See {acceptDefaultAdminTransfer}. + * + * Internal function without access restriction. + */ + function _acceptDefaultAdminTransfer() internal virtual { + (address newAdmin, uint48 schedule) = pendingDefaultAdmin(); + require(_isScheduleSet(schedule) && _hasSchedulePassed(schedule), "AccessControl: transfer delay not passed"); + _revokeRole(DEFAULT_ADMIN_ROLE, defaultAdmin()); + _grantRole(DEFAULT_ADMIN_ROLE, newAdmin); + delete _pendingDefaultAdmin; + delete _pendingDefaultAdminSchedule; + } + + /// + /// AccessControlDefaultAdminRules public and internal setters for defaultAdminDelay/pendingDefaultAdminDelay + /// + + /** + * @inheritdoc IAccessControlDefaultAdminRules + */ + function changeDefaultAdminDelay(uint48 newDelay) public virtual onlyRole(DEFAULT_ADMIN_ROLE) { + _changeDefaultAdminDelay(newDelay); + } + + /** + * @dev See {changeDefaultAdminDelay}. + * + * Internal function without access restriction. + */ + function _changeDefaultAdminDelay(uint48 newDelay) internal virtual { + uint48 newSchedule = SafeCast.toUint48(block.timestamp) + _delayChangeWait(newDelay); + _setPendingDelay(newDelay, newSchedule); + emit DefaultAdminDelayChangeScheduled(newDelay, newSchedule); + } + + /** + * @inheritdoc IAccessControlDefaultAdminRules + */ + function rollbackDefaultAdminDelay() public virtual onlyRole(DEFAULT_ADMIN_ROLE) { + _rollbackDefaultAdminDelay(); + } + + /** + * @dev See {rollbackDefaultAdminDelay}. + * + * Internal function without access restriction. + */ + function _rollbackDefaultAdminDelay() internal virtual { + _setPendingDelay(0, 0); + } + + /** + * @dev Returns the amount of seconds to wait after the `newDelay` will + * become the new {defaultAdminDelay}. + * + * The value returned guarantees that if the delay is reduced, it will go into effect + * after a wait that honors the previously set delay. + * + * See {defaultAdminDelayIncreaseWait}. + */ + function _delayChangeWait(uint48 newDelay) internal view virtual returns (uint48) { + uint48 currentDelay = defaultAdminDelay(); + + // When increasing the delay, we schedule the delay change to occur after a period of "new delay" has passed, up + // to a maximum given by defaultAdminDelayIncreaseWait, by default 5 days. For example, if increasing from 1 day + // to 3 days, the new delay will come into effect after 3 days. If increasing from 1 day to 10 days, the new + // delay will come into effect after 5 days. The 5 day wait period is intended to be able to fix an error like + // using milliseconds instead of seconds. + // + // When decreasing the delay, we wait the difference between "current delay" and "new delay". This guarantees + // that an admin transfer cannot be made faster than "current delay" at the time the delay change is scheduled. + // For example, if decreasing from 10 days to 3 days, the new delay will come into effect after 7 days. + return + newDelay > currentDelay + ? uint48(Math.min(newDelay, defaultAdminDelayIncreaseWait())) // no need to safecast, both inputs are uint48 + : currentDelay - newDelay; + } + + /// + /// Private setters + /// + + /** + * @dev Setter of the tuple for pending admin and its schedule. + * + * May emit a DefaultAdminTransferCanceled event. + */ + function _setPendingDefaultAdmin(address newAdmin, uint48 newSchedule) private { + (, uint48 oldSchedule) = pendingDefaultAdmin(); + + _pendingDefaultAdmin = newAdmin; + _pendingDefaultAdminSchedule = newSchedule; + + // An `oldSchedule` from `pendingDefaultAdmin()` is only set if it hasn't been accepted. + if (_isScheduleSet(oldSchedule)) { + // Emit for implicit cancellations when another default admin was scheduled. + emit DefaultAdminTransferCanceled(); + } + } + + /** + * @dev Setter of the tuple for pending delay and its schedule. + * + * May emit a DefaultAdminDelayChangeCanceled event. + */ + function _setPendingDelay(uint48 newDelay, uint48 newSchedule) private { + uint48 oldSchedule = _pendingDelaySchedule; + + if (_isScheduleSet(oldSchedule)) { + if (_hasSchedulePassed(oldSchedule)) { + // Materialize a virtual delay + _currentDelay = _pendingDelay; + } else { + // Emit for implicit cancellations when another delay was scheduled. + emit DefaultAdminDelayChangeCanceled(); + } + } + + _pendingDelay = newDelay; + _pendingDelaySchedule = newSchedule; + } + + /// + /// Private helpers + /// + + /** + * @dev Defines if an `schedule` is considered set. For consistency purposes. + */ + function _isScheduleSet(uint48 schedule) private pure returns (bool) { + return schedule != 0; + } + + /** + * @dev Defines if an `schedule` is considered passed. For consistency purposes. + */ + function _hasSchedulePassed(uint48 schedule) private view returns (bool) { + return schedule < block.timestamp; } } diff --git a/contracts/access/IAccessControlDefaultAdminRules.sol b/contracts/access/IAccessControlDefaultAdminRules.sol index 753c7c802..d28c49d95 100644 --- a/contracts/access/IAccessControlDefaultAdminRules.sol +++ b/contracts/access/IAccessControlDefaultAdminRules.sol @@ -12,16 +12,27 @@ import "./IAccessControl.sol"; */ interface IAccessControlDefaultAdminRules is IAccessControl { /** - * @dev Emitted when a `DEFAULT_ADMIN_ROLE` transfer is started, setting `newDefaultAdmin` - * as the next default admin, which will have rights to claim the `DEFAULT_ADMIN_ROLE` - * after `defaultAdminTransferDelayedUntil` has passed. + * @dev Emitted when a {defaultAdmin} transfer is started, setting `newAdmin` as the next + * address to become the {defaultAdmin} by calling {acceptDefaultAdminTransfer} only after `acceptSchedule` + * passes. */ - event DefaultAdminRoleChangeStarted(address indexed newDefaultAdmin, uint48 defaultAdminTransferDelayedUntil); + event DefaultAdminTransferScheduled(address indexed newAdmin, uint48 acceptSchedule); /** - * @dev Returns the delay between each `DEFAULT_ADMIN_ROLE` transfer. + * @dev Emitted when a {pendingDefaultAdmin} is reset if it was never accepted, regardless of its schedule. */ - function defaultAdminDelay() external view returns (uint48); + event DefaultAdminTransferCanceled(); + + /** + * @dev Emitted when a {defaultAdminDelay} change is started, setting `newDelay` as the next + * delay to be applied between default admin transfer after `effectSchedule` has passed. + */ + event DefaultAdminDelayChangeScheduled(uint48 newDelay, uint48 effectSchedule); + + /** + * @dev Emitted when a {pendingDefaultAdminDelay} is reset if its schedule didn't pass. + */ + event DefaultAdminDelayChangeCanceled(); /** * @dev Returns the address of the current `DEFAULT_ADMIN_ROLE` holder. @@ -29,45 +40,133 @@ interface IAccessControlDefaultAdminRules is IAccessControl { function defaultAdmin() external view returns (address); /** - * @dev Returns the address of the pending `DEFAULT_ADMIN_ROLE` holder. + * @dev Returns a tuple of a `newAdmin` and an accept schedule. + * + * After the `schedule` passes, the `newAdmin` will be able to accept the {defaultAdmin} role + * by calling {acceptDefaultAdminTransfer}, completing the role transfer. + * + * A zero value only in `acceptSchedule` indicates no pending admin transfer. + * + * NOTE: A zero address `newAdmin` means that {defaultAdmin} is being renounced. */ - function pendingDefaultAdmin() external view returns (address); + function pendingDefaultAdmin() external view returns (address newAdmin, uint48 acceptSchedule); /** - * @dev Returns the timestamp after which the pending default admin can claim the `DEFAULT_ADMIN_ROLE`. + * @dev Returns the delay required to schedule the acceptance of a {defaultAdmin} transfer started. + * + * This delay will be added to the current timestamp when calling {beginDefaultAdminTransfer} to set + * the acceptance schedule. + * + * NOTE: If a delay change has been scheduled, it will take effect as soon as the schedule passes, making this + * function returns the new delay. See {changeDefaultAdminDelay}. */ - function defaultAdminTransferDelayedUntil() external view returns (uint48); + function defaultAdminDelay() external view returns (uint48); /** - * @dev Starts a `DEFAULT_ADMIN_ROLE` transfer by setting a pending default admin - * and a timer to pass. + * @dev Returns a tuple of `newDelay` and an effect schedule. + * + * After the `schedule` passes, the `newDelay` will get into effect immediately for every + * new {defaultAdmin} transfer started with {beginDefaultAdminTransfer}. + * + * A zero value only in `effectSchedule` indicates no pending delay change. + * + * NOTE: A zero value only for `newDelay` means that the next {defaultAdminDelay} + * will be zero after the effect schedule. + */ + function pendingDefaultAdminDelay() external view returns (uint48 newDelay, uint48 effectSchedule); + + /** + * @dev Starts a {defaultAdmin} transfer by setting a {pendingDefaultAdmin} scheduled for acceptance + * after the current timestamp plus a {defaultAdminDelay}. * * Requirements: * - * - Only can be called by the current `DEFAULT_ADMIN_ROLE` holder. + * - Only can be called by the current {defaultAdmin}. * - * Emits a {DefaultAdminRoleChangeStarted}. + * Emits a DefaultAdminRoleChangeStarted event. */ function beginDefaultAdminTransfer(address newAdmin) external; /** - * @dev Completes a `DEFAULT_ADMIN_ROLE` transfer. + * @dev Cancels a {defaultAdmin} transfer previously started with {beginDefaultAdminTransfer}. + * + * A {pendingDefaultAdmin} not yet accepted can also be cancelled with this function. * * Requirements: * - * - Caller should be the pending default admin. + * - Only can be called by the current {defaultAdmin}. + * + * May emit a DefaultAdminTransferCanceled event. + */ + function cancelDefaultAdminTransfer() external; + + /** + * @dev Completes a {defaultAdmin} transfer previously started with {beginDefaultAdminTransfer}. + * + * After calling the function: + * * - `DEFAULT_ADMIN_ROLE` should be granted to the caller. * - `DEFAULT_ADMIN_ROLE` should be revoked from the previous holder. + * - {pendingDefaultAdmin} should be reset to zero values. + * + * Requirements: + * + * - Only can be called by the {pendingDefaultAdmin}'s `newAdmin`. + * - The {pendingDefaultAdmin}'s `acceptSchedule` should've passed. */ function acceptDefaultAdminTransfer() external; /** - * @dev Cancels a `DEFAULT_ADMIN_ROLE` transfer. + * @dev Initiates a {defaultAdminDelay} update by setting a {pendingDefaultAdminDelay} scheduled for getting + * into effect after the current timestamp plus a {defaultAdminDelay}. + * + * This function guarantees that any call to {beginDefaultAdminTransfer} done between the timestamp this + * method is called and the {pendingDefaultAdminDelay} effect schedule will use the current {defaultAdminDelay} + * set before calling. + * + * The {pendingDefaultAdminDelay}'s effect schedule is defined in a way that waiting until the schedule and then + * calling {beginDefaultAdminTransfer} with the new delay will take at least the same as another {defaultAdmin} + * complete transfer (including acceptance). + * + * The schedule is designed for two scenarios: + * + * - When the delay is changed for a larger one the schedule is `block.timestamp + newDelay` capped by + * {defaultAdminDelayIncreaseWait}. + * - When the delay is changed for a shorter one, the schedule is `block.timestamp + (current delay - new delay)`. + * + * A {pendingDefaultAdminDelay} that never got into effect will be canceled in favor of a new scheduled change. * * Requirements: * - * - Can be called even after the timer has passed. - * - Can only be called by the current `DEFAULT_ADMIN_ROLE` holder. + * - Only can be called by the current {defaultAdmin}. + * + * Emits a DefaultAdminDelayChangeScheduled event and may emit a DefaultAdminDelayChangeCanceled event. */ - function cancelDefaultAdminTransfer() external; + function changeDefaultAdminDelay(uint48 newDelay) external; + + /** + * @dev Cancels a scheduled {defaultAdminDelay} change. + * + * Requirements: + * + * - Only can be called by the current {defaultAdmin}. + * + * May emit a DefaultAdminDelayChangeCanceled event. + */ + function rollbackDefaultAdminDelay() external; + + /** + * @dev Maximum time in seconds for an increase to {defaultAdminDelay} (that is scheduled using {changeDefaultAdminDelay}) + * to take effect. Default to 5 days. + * + * When the {defaultAdminDelay} is scheduled to be increased, it goes into effect after the new delay has passed with + * the purpose of giving enough time for reverting any accidental change (i.e. using milliseconds instead of seconds) + * that may lock the contract. However, to avoid excessive schedules, the wait is capped by this function and it can + * be overrode for a custom {defaultAdminDelay} increase scheduling. + * + * IMPORTANT: Make sure to add a reasonable amount of time while overriding this value, otherwise, + * there's a risk of setting a high new delay that goes into effect almost immediately without the + * possibility of human intervention in the case of an input error (eg. set milliseconds instead of seconds). + */ + function defaultAdminDelayIncreaseWait() external view returns (uint48); } diff --git a/test/access/AccessControl.behavior.js b/test/access/AccessControl.behavior.js index e04c5a165..6c88aa274 100644 --- a/test/access/AccessControl.behavior.js +++ b/test/access/AccessControl.behavior.js @@ -1,13 +1,16 @@ -const { expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); -const { ZERO_ADDRESS } = require('@openzeppelin/test-helpers/src/constants'); +const { expectEvent, expectRevert, constants, BN } = require('@openzeppelin/test-helpers'); const { expect } = require('chai'); + const { time } = require('@nomicfoundation/hardhat-network-helpers'); const { shouldSupportInterfaces } = require('../utils/introspection/SupportsInterface.behavior'); +const { network } = require('hardhat'); +const { ZERO_ADDRESS } = require('@openzeppelin/test-helpers/src/constants'); const DEFAULT_ADMIN_ROLE = '0x0000000000000000000000000000000000000000000000000000000000000000'; const ROLE = web3.utils.soliditySha3('ROLE'); const OTHER_ROLE = web3.utils.soliditySha3('OTHER_ROLE'); +const ZERO = web3.utils.toBN(0); function shouldBehaveLikeAccessControl(errorPrefix, admin, authorized, other, otherAdmin) { shouldSupportInterfaces(['AccessControl']); @@ -215,18 +218,151 @@ function shouldBehaveLikeAccessControlEnumerable(errorPrefix, admin, authorized, function shouldBehaveLikeAccessControlDefaultAdminRules(errorPrefix, delay, defaultAdmin, newDefaultAdmin, other) { shouldSupportInterfaces(['AccessControlDefaultAdminRules']); - it('has a default disabled delayed until', async function () { - expect(await this.accessControl.defaultAdminTransferDelayedUntil()).to.be.bignumber.equal(web3.utils.toBN(0)); + function expectNoEvent(receipt, eventName) { + try { + expectEvent(receipt, eventName); + throw new Error(`${eventName} event found`); + } catch (err) { + expect(err.message).to.eq(`No '${eventName}' events found: expected false to equal true`); + } + } + + for (const getter of ['owner', 'defaultAdmin']) { + describe(`${getter}()`, function () { + it('has a default set to the initial default admin', async function () { + const value = await this.accessControl[getter](); + expect(value).to.equal(defaultAdmin); + expect(await this.accessControl.hasRole(DEFAULT_ADMIN_ROLE, value)).to.be.true; + }); + + it('changes if the default admin changes', async function () { + // Starts an admin transfer + await this.accessControl.beginDefaultAdminTransfer(newDefaultAdmin, { from: defaultAdmin }); + + // Wait for acceptance + const acceptSchedule = web3.utils.toBN(await time.latest()).add(delay); + await time.setNextBlockTimestamp(acceptSchedule.addn(1)); + await this.accessControl.acceptDefaultAdminTransfer({ from: newDefaultAdmin }); + + const value = await this.accessControl[getter](); + expect(value).to.equal(newDefaultAdmin); + }); + }); + } + + describe('pendingDefaultAdmin()', function () { + it('returns 0 if no pending default admin transfer', async function () { + const { newAdmin, schedule } = await this.accessControl.pendingDefaultAdmin(); + expect(newAdmin).to.eq(ZERO_ADDRESS); + expect(schedule).to.be.bignumber.eq(ZERO); + }); + + describe('when there is a scheduled default admin transfer', function () { + beforeEach('begins admin transfer', async function () { + await this.accessControl.beginDefaultAdminTransfer(newDefaultAdmin, { from: defaultAdmin }); + }); + + for (const [fromSchedule, tag] of [ + [-1, 'before'], + [0, 'exactly when'], + [1, 'after'], + ]) { + it(`returns pending admin and delay ${tag} delay schedule passes if not accepted`, async function () { + // Wait until schedule + fromSchedule + const { schedule: firstSchedule } = await this.accessControl.pendingDefaultAdmin(); + await time.setNextBlockTimestamp(firstSchedule.toNumber() + fromSchedule); + await network.provider.send('evm_mine'); // Mine a block to force the timestamp + + const { newAdmin, schedule } = await this.accessControl.pendingDefaultAdmin(); + expect(newAdmin).to.eq(newDefaultAdmin); + expect(schedule).to.be.bignumber.eq(firstSchedule); + }); + } + + it('returns 0 after delay schedule passes and the transfer was accepted', async function () { + // Wait after schedule + const { schedule: firstSchedule } = await this.accessControl.pendingDefaultAdmin(); + await time.setNextBlockTimestamp(firstSchedule.addn(1)); + + // Accepts + await this.accessControl.acceptDefaultAdminTransfer({ from: newDefaultAdmin }); + + const { newAdmin, schedule } = await this.accessControl.pendingDefaultAdmin(); + expect(newAdmin).to.eq(ZERO_ADDRESS); + expect(schedule).to.be.bignumber.eq(ZERO); + }); + }); }); - it('has a default pending default admin', async function () { - expect(await this.accessControl.pendingDefaultAdmin()).to.equal(ZERO_ADDRESS); + describe('defaultAdminDelay()', function () { + it('returns the current delay', async function () { + expect(await this.accessControl.defaultAdminDelay()).to.be.bignumber.eq(delay); + }); + + describe('when there is a scheduled delay change', function () { + const newDelay = web3.utils.toBN(0xdead); // Any change + + beforeEach('begins delay change', async function () { + await this.accessControl.changeDefaultAdminDelay(newDelay, { from: defaultAdmin }); + }); + + for (const [fromSchedule, tag, expectedDelay, delayTag] of [ + [-1, 'before', delay, 'old'], + [0, 'exactly when', delay, 'old'], + [1, 'after', newDelay, 'new'], + ]) { + it(`returns ${delayTag} delay ${tag} delay schedule passes`, async function () { + // Wait until schedule + fromSchedule + const { schedule } = await this.accessControl.pendingDefaultAdminDelay(); + await time.setNextBlockTimestamp(schedule.toNumber() + fromSchedule); + await network.provider.send('evm_mine'); // Mine a block to force the timestamp + + const currentDelay = await this.accessControl.defaultAdminDelay(); + expect(currentDelay).to.be.bignumber.eq(expectedDelay); + }); + } + }); }); - it('has a default current owner set to the initial default admin', async function () { - const owner = await this.accessControl.owner(); - expect(owner).to.equal(defaultAdmin); - expect(await this.accessControl.hasRole(DEFAULT_ADMIN_ROLE, owner)).to.be.true; + describe('pendingDefaultAdminDelay()', function () { + it('returns 0 if not set', async function () { + const { newDelay, schedule } = await this.accessControl.pendingDefaultAdminDelay(); + expect(newDelay).to.be.bignumber.eq(ZERO); + expect(schedule).to.be.bignumber.eq(ZERO); + }); + + describe('when there is a scheduled delay change', function () { + const newDelay = web3.utils.toBN(0xdead); // Any change + + beforeEach('begins admin transfer', async function () { + await this.accessControl.changeDefaultAdminDelay(newDelay, { from: defaultAdmin }); + }); + + for (const [fromSchedule, tag, expectedDelay, delayTag, expectZeroSchedule] of [ + [-1, 'before', newDelay, 'new'], + [0, 'exactly when', newDelay, 'new'], + [1, 'after', ZERO, 'zero', true], + ]) { + it(`returns ${delayTag} delay ${tag} delay schedule passes`, async function () { + // Wait until schedule + fromSchedule + const { schedule: firstSchedule } = await this.accessControl.pendingDefaultAdminDelay(); + await time.setNextBlockTimestamp(firstSchedule.toNumber() + fromSchedule); + await network.provider.send('evm_mine'); // Mine a block to force the timestamp + + const { newDelay, schedule } = await this.accessControl.pendingDefaultAdminDelay(); + expect(newDelay).to.be.bignumber.eq(expectedDelay); + expect(schedule).to.be.bignumber.eq(expectZeroSchedule ? ZERO : firstSchedule); + }); + } + }); + }); + + describe('defaultAdminDelayIncreaseWait()', function () { + it('should return 5 days (default)', async function () { + expect(await this.accessControl.defaultAdminDelayIncreaseWait()).to.be.bignumber.eq( + web3.utils.toBN(time.duration.days(5)), + ); + }); }); it('should revert if granting default admin role', async function () { @@ -257,72 +393,130 @@ function shouldBehaveLikeAccessControlDefaultAdminRules(errorPrefix, delay, defa ); }); - describe('begins transfer of default admin', function () { + describe('begins a default admin transfer', function () { let receipt; - let defaultAdminTransferDelayedUntil; + let acceptSchedule; - beforeEach('begins admin transfer', async function () { - receipt = await this.accessControl.beginDefaultAdminTransfer(newDefaultAdmin, { from: defaultAdmin }); - defaultAdminTransferDelayedUntil = web3.utils.toBN(await time.latest()).add(delay); - }); - - it('should set pending default admin and delayed until', async function () { - expect(await this.accessControl.pendingDefaultAdmin()).to.equal(newDefaultAdmin); - expect(await this.accessControl.defaultAdminTransferDelayedUntil()).to.be.bignumber.equal( - defaultAdminTransferDelayedUntil, - ); - expectEvent(receipt, 'DefaultAdminRoleChangeStarted', { - newDefaultAdmin, - defaultAdminTransferDelayedUntil, - }); - }); - - it('should be able to begin a transfer again before delay pass', async function () { - // Time passes just before delay - await time.setNextBlockTimestamp(defaultAdminTransferDelayedUntil.subn(1)); - - // defaultAdmin changes its mind and begin again to another address - await this.accessControl.beginDefaultAdminTransfer(other, { from: defaultAdmin }); - const newDelayedUntil = web3.utils.toBN(await time.latest()).add(delay); - expect(await this.accessControl.pendingDefaultAdmin()).to.equal(other); - expect(await this.accessControl.defaultAdminTransferDelayedUntil()).to.be.bignumber.equal(newDelayedUntil); - }); - - it('should be able to begin a transfer again after delay pass if not accepted', async function () { - // Time passes after delay without acceptance - await time.setNextBlockTimestamp(defaultAdminTransferDelayedUntil.addn(1)); - - // defaultAdmin changes its mind and begin again to another address - await this.accessControl.beginDefaultAdminTransfer(other, { from: defaultAdmin }); - const newDelayedUntil = web3.utils.toBN(await time.latest()).add(delay); - expect(await this.accessControl.pendingDefaultAdmin()).to.equal(other); - expect(await this.accessControl.defaultAdminTransferDelayedUntil()).to.be.bignumber.equal(newDelayedUntil); - }); - - it('should revert if it is called by non-admin accounts', async function () { + it('reverts if called by non default admin accounts', async function () { await expectRevert( this.accessControl.beginDefaultAdminTransfer(newDefaultAdmin, { from: other }), `${errorPrefix}: account ${other.toLowerCase()} is missing role ${DEFAULT_ADMIN_ROLE}`, ); }); + + describe('when there is no pending delay nor pending admin transfer', function () { + beforeEach('begins admin transfer', async function () { + receipt = await this.accessControl.beginDefaultAdminTransfer(newDefaultAdmin, { from: defaultAdmin }); + acceptSchedule = web3.utils.toBN(await time.latest()).add(delay); + }); + + it('should set pending default admin and schedule', async function () { + const { newAdmin, schedule } = await this.accessControl.pendingDefaultAdmin(); + expect(newAdmin).to.equal(newDefaultAdmin); + expect(schedule).to.be.bignumber.equal(acceptSchedule); + expectEvent(receipt, 'DefaultAdminTransferScheduled', { + newAdmin, + acceptSchedule, + }); + }); + }); + + describe('when there is a pending admin transfer', function () { + beforeEach('sets a pending default admin transfer', async function () { + await this.accessControl.beginDefaultAdminTransfer(newDefaultAdmin, { from: defaultAdmin }); + acceptSchedule = web3.utils.toBN(await time.latest()).add(delay); + }); + + for (const [fromSchedule, tag] of [ + [-1, 'before'], + [0, 'exactly when'], + [1, 'after'], + ]) { + it(`should be able to begin a transfer again ${tag} acceptSchedule passes`, async function () { + // Wait until schedule + fromSchedule + await time.setNextBlockTimestamp(acceptSchedule.toNumber() + fromSchedule); + + // defaultAdmin changes its mind and begin again to another address + const receipt = await this.accessControl.beginDefaultAdminTransfer(other, { from: defaultAdmin }); + const newSchedule = web3.utils.toBN(await time.latest()).add(delay); + const { newAdmin, schedule } = await this.accessControl.pendingDefaultAdmin(); + expect(newAdmin).to.equal(other); + expect(schedule).to.be.bignumber.equal(newSchedule); + + // Cancellation is always emitted since it was never accepted + expectEvent(receipt, 'DefaultAdminTransferCanceled'); + }); + } + + it('should not emit a cancellation event if the new default admin accepted', async function () { + // Wait until the acceptSchedule has passed + await time.setNextBlockTimestamp(acceptSchedule.addn(1)); + + // Accept and restart + await this.accessControl.acceptDefaultAdminTransfer({ from: newDefaultAdmin }); + const receipt = await this.accessControl.beginDefaultAdminTransfer(other, { from: newDefaultAdmin }); + + expectNoEvent(receipt, 'DefaultAdminTransferCanceled'); + }); + }); + + describe('when there is a pending delay', function () { + const newDelay = web3.utils.toBN(time.duration.hours(3)); + + beforeEach('schedule a delay change', async function () { + await this.accessControl.changeDefaultAdminDelay(newDelay, { from: defaultAdmin }); + const pendingDefaultAdminDelay = await this.accessControl.pendingDefaultAdminDelay(); + acceptSchedule = pendingDefaultAdminDelay.schedule; + }); + + for (const [fromSchedule, schedulePassed, expectedDelay, delayTag] of [ + [-1, 'before', delay, 'old'], + [0, 'exactly when', delay, 'old'], + [1, 'after', newDelay, 'new'], + ]) { + it(`should set the ${delayTag} delay and apply it to next default admin transfer schedule ${schedulePassed} acceptSchedule passed`, async function () { + // Wait until the expected fromSchedule time + await time.setNextBlockTimestamp(acceptSchedule.toNumber() + fromSchedule); + + // Start the new default admin transfer and get its schedule + const receipt = await this.accessControl.beginDefaultAdminTransfer(newDefaultAdmin, { from: defaultAdmin }); + const expectedAcceptSchedule = web3.utils.toBN(await time.latest()).add(expectedDelay); + + // Check that the schedule corresponds with the new delay + const { newAdmin, schedule: transferSchedule } = await this.accessControl.pendingDefaultAdmin(); + expect(newAdmin).to.equal(newDefaultAdmin); + expect(transferSchedule).to.be.bignumber.equal(expectedAcceptSchedule); + + expectEvent(receipt, 'DefaultAdminTransferScheduled', { + newAdmin, + acceptSchedule: expectedAcceptSchedule, + }); + }); + } + }); }); describe('accepts transfer admin', function () { - let delayPassed; + let acceptSchedule; beforeEach(async function () { await this.accessControl.beginDefaultAdminTransfer(newDefaultAdmin, { from: defaultAdmin }); - delayPassed = web3.utils - .toBN(await time.latest()) - .add(delay) - .addn(1); + acceptSchedule = web3.utils.toBN(await time.latest()).add(delay); }); - describe('caller is pending default admin and delay has passed', function () { + it('should revert if caller is not pending default admin', async function () { + await time.setNextBlockTimestamp(acceptSchedule.addn(1)); + await expectRevert( + this.accessControl.acceptDefaultAdminTransfer({ from: other }), + `${errorPrefix}: pending admin must accept`, + ); + }); + + describe('when caller is pending default admin and delay has passed', function () { let from; beforeEach(async function () { - await time.setNextBlockTimestamp(delayPassed); + await time.setNextBlockTimestamp(acceptSchedule.addn(1)); from = newDefaultAdmin; }); @@ -344,108 +538,122 @@ function shouldBehaveLikeAccessControlDefaultAdminRules(errorPrefix, delay, defa account: newDefaultAdmin, }); - // Resets pending default admin and delayed until - expect(await this.accessControl.defaultAdminTransferDelayedUntil()).to.be.bignumber.equal(web3.utils.toBN(0)); - expect(await this.accessControl.pendingDefaultAdmin()).to.equal(ZERO_ADDRESS); + // Resets pending default admin and schedule + const { newAdmin, schedule } = await this.accessControl.pendingDefaultAdmin(); + expect(newAdmin).to.equal(constants.ZERO_ADDRESS); + expect(schedule).to.be.bignumber.equal(ZERO); }); }); - it('should revert if caller is not pending default admin', async function () { - await time.setNextBlockTimestamp(delayPassed); - await expectRevert( - this.accessControl.acceptDefaultAdminTransfer({ from: other }), - `${errorPrefix}: pending admin must accept`, - ); - }); - - describe('delayedUntil not passed', function () { - let delayNotPassed; - - beforeEach(function () { - delayNotPassed = delayPassed.subn(1); - }); - - it('should revert if block.timestamp is equal to delayed until', async function () { - await time.setNextBlockTimestamp(delayNotPassed); - await expectRevert( - this.accessControl.acceptDefaultAdminTransfer({ from: newDefaultAdmin }), - `${errorPrefix}: transfer delay not passed`, - ); - }); - - it('should revert if block.timestamp is less than delayed until', async function () { - await expectRevert( - this.accessControl.acceptDefaultAdminTransfer({ from: newDefaultAdmin }), - `${errorPrefix}: transfer delay not passed`, - ); - }); + describe('schedule not passed', function () { + for (const [fromSchedule, tag] of [ + [-1, 'less'], + [0, 'equal'], + ]) { + it(`should revert if block.timestamp is ${tag} to schedule`, async function () { + await time.setNextBlockTimestamp(acceptSchedule.toNumber() + fromSchedule); + await expectRevert( + this.accessControl.acceptDefaultAdminTransfer({ from: newDefaultAdmin }), + `${errorPrefix}: transfer delay not passed`, + ); + }); + } }); }); - describe('cancel transfer default admin', function () { - let delayPassed; - - beforeEach(async function () { - await this.accessControl.beginDefaultAdminTransfer(newDefaultAdmin, { from: defaultAdmin }); - delayPassed = web3.utils - .toBN(await time.latest()) - .add(delay) - .addn(1); - }); - - it('resets pending default admin and delayed until', async function () { - await this.accessControl.cancelDefaultAdminTransfer({ from: defaultAdmin }); - expect(await this.accessControl.defaultAdminTransferDelayedUntil()).to.be.bignumber.equal(web3.utils.toBN(0)); - expect(await this.accessControl.pendingDefaultAdmin()).to.equal(ZERO_ADDRESS); - - // Advance until passed delay - await time.setNextBlockTimestamp(delayPassed); - - // Previous pending default admin should not be able to accept after cancellation. - await expectRevert( - this.accessControl.acceptDefaultAdminTransfer({ from: newDefaultAdmin }), - `${errorPrefix}: pending admin must accept`, - ); - }); - - it('cancels even after delay has passed', async function () { - await this.accessControl.cancelDefaultAdminTransfer({ from: defaultAdmin }); - await time.setNextBlockTimestamp(delayPassed); - expect(await this.accessControl.defaultAdminTransferDelayedUntil()).to.be.bignumber.equal(web3.utils.toBN(0)); - expect(await this.accessControl.pendingDefaultAdmin()).to.equal(ZERO_ADDRESS); - }); - + describe('cancels a default admin transfer', function () { it('reverts if called by non default admin accounts', async function () { await expectRevert( this.accessControl.cancelDefaultAdminTransfer({ from: other }), `${errorPrefix}: account ${other.toLowerCase()} is missing role ${DEFAULT_ADMIN_ROLE}`, ); }); + + describe('when there is a pending default admin transfer', function () { + let acceptSchedule; + + beforeEach(async function () { + await this.accessControl.beginDefaultAdminTransfer(newDefaultAdmin, { from: defaultAdmin }); + acceptSchedule = web3.utils.toBN(await time.latest()).add(delay); + }); + + for (const [fromSchedule, tag] of [ + [-1, 'before'], + [0, 'exactly when'], + [1, 'after'], + ]) { + it(`resets pending default admin and schedule ${tag} transfer schedule passes`, async function () { + // Advance until passed delay + await time.setNextBlockTimestamp(acceptSchedule.toNumber() + fromSchedule); + + const receipt = await this.accessControl.cancelDefaultAdminTransfer({ from: defaultAdmin }); + + const { newAdmin, schedule } = await this.accessControl.pendingDefaultAdmin(); + expect(newAdmin).to.equal(constants.ZERO_ADDRESS); + expect(schedule).to.be.bignumber.equal(ZERO); + + expectEvent(receipt, 'DefaultAdminTransferCanceled'); + }); + } + + it('should revert if the previous default admin tries to accept', async function () { + await this.accessControl.cancelDefaultAdminTransfer({ from: defaultAdmin }); + + // Advance until passed delay + await time.setNextBlockTimestamp(acceptSchedule.addn(1)); + + // Previous pending default admin should not be able to accept after cancellation. + await expectRevert( + this.accessControl.acceptDefaultAdminTransfer({ from: newDefaultAdmin }), + `${errorPrefix}: pending admin must accept`, + ); + }); + }); + + describe('when there is no pending default admin transfer', async function () { + it('should succeed without changes', async function () { + const receipt = await this.accessControl.cancelDefaultAdminTransfer({ from: defaultAdmin }); + + const { newAdmin, schedule } = await this.accessControl.pendingDefaultAdmin(); + expect(newAdmin).to.equal(constants.ZERO_ADDRESS); + expect(schedule).to.be.bignumber.equal(ZERO); + + expectNoEvent(receipt, 'DefaultAdminTransferCanceled'); + }); + }); }); - describe('renouncing admin', function () { + describe('renounces admin', function () { let delayPassed; let from = defaultAdmin; beforeEach(async function () { - await this.accessControl.beginDefaultAdminTransfer(ZERO_ADDRESS, { from }); + await this.accessControl.beginDefaultAdminTransfer(constants.ZERO_ADDRESS, { from }); delayPassed = web3.utils .toBN(await time.latest()) .add(delay) .addn(1); }); - it('it renounces role', async function () { + it('reverts if caller is not default admin', async function () { + await time.setNextBlockTimestamp(delayPassed); + await expectRevert( + this.accessControl.renounceRole(DEFAULT_ADMIN_ROLE, other, { from }), + `${errorPrefix}: can only renounce roles for self`, + ); + }); + + it('renounces role', async function () { await time.setNextBlockTimestamp(delayPassed); const receipt = await this.accessControl.renounceRole(DEFAULT_ADMIN_ROLE, from, { from }); expect(await this.accessControl.hasRole(DEFAULT_ADMIN_ROLE, defaultAdmin)).to.be.false; - expect(await this.accessControl.hasRole(ZERO_ADDRESS, defaultAdmin)).to.be.false; + expect(await this.accessControl.hasRole(constants.ZERO_ADDRESS, defaultAdmin)).to.be.false; expectEvent(receipt, 'RoleRevoked', { role: DEFAULT_ADMIN_ROLE, account: from, }); - expect(await this.accessControl.owner()).to.equal(ZERO_ADDRESS); + expect(await this.accessControl.owner()).to.equal(constants.ZERO_ADDRESS); }); it('allows to recover access using the internal _grantRole', async function () { @@ -459,35 +667,180 @@ function shouldBehaveLikeAccessControlDefaultAdminRules(errorPrefix, delay, defa }); }); - it('reverts if caller is not default admin', async function () { - await time.setNextBlockTimestamp(delayPassed); - await expectRevert( - this.accessControl.renounceRole(DEFAULT_ADMIN_ROLE, other, { from }), - `${errorPrefix}: can only renounce roles for self`, - ); - }); - - describe('delayed until not passed', function () { + describe('schedule not passed', function () { let delayNotPassed; beforeEach(function () { delayNotPassed = delayPassed.subn(1); }); - it('reverts if block.timestamp is equal to delayed until', async function () { - await time.setNextBlockTimestamp(delayNotPassed); - await expectRevert( - this.accessControl.renounceRole(DEFAULT_ADMIN_ROLE, defaultAdmin, { from }), - `${errorPrefix}: only can renounce in two delayed steps`, - ); + for (const [fromSchedule, tag] of [ + [-1, 'less'], + [0, 'equal'], + ]) { + it(`reverts if block.timestamp is ${tag} to schedule`, async function () { + await time.setNextBlockTimestamp(delayNotPassed.toNumber() + fromSchedule); + await expectRevert( + this.accessControl.renounceRole(DEFAULT_ADMIN_ROLE, defaultAdmin, { from }), + `${errorPrefix}: only can renounce in two delayed steps`, + ); + }); + } + }); + }); + + describe('changes delay', function () { + it('reverts if called by non default admin accounts', async function () { + await expectRevert( + this.accessControl.changeDefaultAdminDelay(time.duration.hours(4), { + from: other, + }), + `${errorPrefix}: account ${other.toLowerCase()} is missing role ${DEFAULT_ADMIN_ROLE}`, + ); + }); + + for (const [newDefaultAdminDelay, delayChangeType] of [ + [web3.utils.toBN(delay).subn(time.duration.hours(1)), 'decreased'], + [web3.utils.toBN(delay).addn(time.duration.hours(1)), 'increased'], + [web3.utils.toBN(delay).addn(time.duration.days(5)), 'increased to more than 5 days'], + ]) { + describe(`when the delay is ${delayChangeType}`, function () { + it('begins the delay change to the new delay', async function () { + // Begins the change + const receipt = await this.accessControl.changeDefaultAdminDelay(newDefaultAdminDelay, { + from: defaultAdmin, + }); + + // Calculate expected values + const cap = await this.accessControl.defaultAdminDelayIncreaseWait(); + const changeDelay = newDefaultAdminDelay.lte(delay) + ? delay.sub(newDefaultAdminDelay) + : BN.min(newDefaultAdminDelay, cap); + const timestamp = web3.utils.toBN(await time.latest()); + const effectSchedule = timestamp.add(changeDelay); + + // Assert + const { newDelay, schedule } = await this.accessControl.pendingDefaultAdminDelay(); + expect(newDelay).to.be.bignumber.eq(newDefaultAdminDelay); + expect(schedule).to.be.bignumber.eq(effectSchedule); + expectEvent(receipt, 'DefaultAdminDelayChangeScheduled', { + newDelay, + effectSchedule, + }); + }); + + describe('scheduling again', function () { + beforeEach('schedule once', async function () { + await this.accessControl.changeDefaultAdminDelay(newDefaultAdminDelay, { from: defaultAdmin }); + }); + + for (const [fromSchedule, tag] of [ + [-1, 'before'], + [0, 'exactly when'], + [1, 'after'], + ]) { + const passed = fromSchedule > 0; + + it(`succeeds ${tag} the delay schedule passes`, async function () { + // Wait until schedule + fromSchedule + const { schedule: firstSchedule } = await this.accessControl.pendingDefaultAdminDelay(); + await time.setNextBlockTimestamp(firstSchedule.toNumber() + fromSchedule); + + // Default admin changes its mind and begins another delay change + const anotherNewDefaultAdminDelay = newDefaultAdminDelay.addn(time.duration.hours(2)); + const receipt = await this.accessControl.changeDefaultAdminDelay(anotherNewDefaultAdminDelay, { + from: defaultAdmin, + }); + + // Calculate expected values + const cap = await this.accessControl.defaultAdminDelayIncreaseWait(); + const timestamp = web3.utils.toBN(await time.latest()); + const effectSchedule = timestamp.add(BN.min(cap, anotherNewDefaultAdminDelay)); + + // Assert + const { newDelay, schedule } = await this.accessControl.pendingDefaultAdminDelay(); + expect(newDelay).to.be.bignumber.eq(anotherNewDefaultAdminDelay); + expect(schedule).to.be.bignumber.eq(effectSchedule); + expectEvent(receipt, 'DefaultAdminDelayChangeScheduled', { + newDelay, + effectSchedule, + }); + }); + + const emit = passed ? 'not emit' : 'emit'; + it(`should ${emit} a cancellation event ${tag} the delay schedule passes`, async function () { + // Wait until schedule + fromSchedule + const { schedule: firstSchedule } = await this.accessControl.pendingDefaultAdminDelay(); + await time.setNextBlockTimestamp(firstSchedule.toNumber() + fromSchedule); + + // Default admin changes its mind and begins another delay change + const anotherNewDefaultAdminDelay = newDefaultAdminDelay.addn(time.duration.hours(2)); + const receipt = await this.accessControl.changeDefaultAdminDelay(anotherNewDefaultAdminDelay, { + from: defaultAdmin, + }); + + const eventMatcher = passed ? expectNoEvent : expectEvent; + eventMatcher(receipt, 'DefaultAdminDelayChangeCanceled'); + }); + } + }); + }); + } + }); + + describe('rollbacks a delay change', function () { + it('reverts if called by non default admin accounts', async function () { + await expectRevert( + this.accessControl.rollbackDefaultAdminDelay({ from: other }), + `${errorPrefix}: account ${other.toLowerCase()} is missing role ${DEFAULT_ADMIN_ROLE}`, + ); + }); + + describe('when there is a pending delay', function () { + beforeEach('set pending delay', async function () { + await this.accessControl.changeDefaultAdminDelay(time.duration.hours(12), { from: defaultAdmin }); }); - it('reverts if block.timestamp is less than delayed until', async function () { - await time.setNextBlockTimestamp(delayNotPassed.subn(1)); - await expectRevert( - this.accessControl.renounceRole(DEFAULT_ADMIN_ROLE, defaultAdmin, { from }), - `${errorPrefix}: only can renounce in two delayed steps`, - ); + for (const [fromSchedule, tag] of [ + [-1, 'before'], + [0, 'exactly when'], + [1, 'after'], + ]) { + const passed = fromSchedule > 0; + + it(`resets pending delay and schedule ${tag} delay change schedule passes`, async function () { + // Wait until schedule + fromSchedule + const { schedule: firstSchedule } = await this.accessControl.pendingDefaultAdminDelay(); + await time.setNextBlockTimestamp(firstSchedule.toNumber() + fromSchedule); + + await this.accessControl.rollbackDefaultAdminDelay({ from: defaultAdmin }); + + const { newDelay, schedule } = await this.accessControl.pendingDefaultAdminDelay(); + expect(newDelay).to.be.bignumber.eq(ZERO); + expect(schedule).to.be.bignumber.eq(ZERO); + }); + + const emit = passed ? 'not emit' : 'emit'; + it(`should ${emit} a cancellation event ${tag} the delay schedule passes`, async function () { + // Wait until schedule + fromSchedule + const { schedule: firstSchedule } = await this.accessControl.pendingDefaultAdminDelay(); + await time.setNextBlockTimestamp(firstSchedule.toNumber() + fromSchedule); + + const receipt = await this.accessControl.rollbackDefaultAdminDelay({ from: defaultAdmin }); + + const eventMatcher = passed ? expectNoEvent : expectEvent; + eventMatcher(receipt, 'DefaultAdminDelayChangeCanceled'); + }); + } + }); + + describe('when there is no pending delay', function () { + it('succeeds without changes', async function () { + await this.accessControl.rollbackDefaultAdminDelay({ from: defaultAdmin }); + + const { newDelay, schedule } = await this.accessControl.pendingDefaultAdminDelay(); + expect(newDelay).to.be.bignumber.eq(ZERO); + expect(schedule).to.be.bignumber.eq(ZERO); }); }); }); diff --git a/test/access/AccessControlDefaultAdminRules.test.js b/test/access/AccessControlDefaultAdminRules.test.js index 2a23d3b6d..4e3167a46 100644 --- a/test/access/AccessControlDefaultAdminRules.test.js +++ b/test/access/AccessControlDefaultAdminRules.test.js @@ -7,7 +7,7 @@ const { const AccessControlDefaultAdminRules = artifacts.require('$AccessControlDefaultAdminRules'); contract('AccessControlDefaultAdminRules', function (accounts) { - const delay = web3.utils.toBN(time.duration.days(10)); + const delay = web3.utils.toBN(time.duration.hours(10)); beforeEach(async function () { this.accessControl = await AccessControlDefaultAdminRules.new(delay, accounts[0], { from: accounts[0] }); diff --git a/test/utils/introspection/SupportsInterface.behavior.js b/test/utils/introspection/SupportsInterface.behavior.js index 5ffe242ed..541f6c611 100644 --- a/test/utils/introspection/SupportsInterface.behavior.js +++ b/test/utils/introspection/SupportsInterface.behavior.js @@ -39,9 +39,12 @@ const INTERFACES = { AccessControlEnumerable: ['getRoleMember(bytes32,uint256)', 'getRoleMemberCount(bytes32)'], AccessControlDefaultAdminRules: [ 'defaultAdminDelay()', + 'pendingDefaultAdminDelay()', 'defaultAdmin()', - 'defaultAdminTransferDelayedUntil()', 'pendingDefaultAdmin()', + 'defaultAdminDelayIncreaseWait()', + 'changeDefaultAdminDelay(uint48)', + 'rollbackDefaultAdminDelay()', 'beginDefaultAdminTransfer(address)', 'acceptDefaultAdminTransfer()', 'cancelDefaultAdminTransfer()', From 7e7060e00e107460fc57c178859d3cf0c6ac64ef Mon Sep 17 00:00:00 2001 From: Antonio Viggiano Date: Thu, 30 Mar 2023 15:57:09 -0300 Subject: [PATCH 088/133] Update IERC3156FlashBorrower.sol (#4145) --- contracts/interfaces/IERC3156FlashBorrower.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/interfaces/IERC3156FlashBorrower.sol b/contracts/interfaces/IERC3156FlashBorrower.sol index c3b4f1eb1..0428391fc 100644 --- a/contracts/interfaces/IERC3156FlashBorrower.sol +++ b/contracts/interfaces/IERC3156FlashBorrower.sol @@ -17,7 +17,7 @@ interface IERC3156FlashBorrower { * @param amount The amount of tokens lent. * @param fee The additional amount of tokens to repay. * @param data Arbitrary data structure, intended to contain user-defined parameters. - * @return The keccak256 hash of "IERC3156FlashBorrower.onFlashLoan" + * @return The keccak256 hash of "ERC3156FlashBorrower.onFlashLoan" */ function onFlashLoan( address initiator, From ead3bcaccbc0ae02f0aaa1b294b432ac55f758cf Mon Sep 17 00:00:00 2001 From: Francisco Date: Tue, 4 Apr 2023 23:05:39 -0300 Subject: [PATCH 089/133] Fix spurious CI check failures (#4160) --- .github/workflows/checks.yml | 2 ++ foundry.toml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index c37bf935b..290c6a943 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -83,6 +83,8 @@ jobs: uses: ./.github/actions/setup - run: rm foundry.toml - uses: crytic/slither-action@v0.3.0 + with: + node-version: 18 codespell: if: github.repository != 'OpenZeppelin/openzeppelin-contracts-upgradeable' diff --git a/foundry.toml b/foundry.toml index c0da48773..d0aa4ea39 100644 --- a/foundry.toml +++ b/foundry.toml @@ -1,3 +1,3 @@ [fuzz] runs = 10000 -max_test_rejects = 100000 +max_test_rejects = 150000 From 5523c1482bd0a503e4c4dfe821bd2f6b523f3c86 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Wed, 5 Apr 2023 16:57:08 +0200 Subject: [PATCH 090/133] Fix TransparentUpgradeableProxy's transparency (#4154) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Francisco Co-authored-by: Ernesto García --- .changeset/thirty-shrimps-mix.md | 5 + contracts/interfaces/IERC1967.sol | 25 +++++ contracts/proxy/ERC1967/ERC1967Upgrade.sol | 18 +-- contracts/proxy/transparent/ProxyAdmin.sol | 10 +- .../TransparentUpgradeableProxy.sol | 103 +++++++++++++----- test/proxy/transparent/ProxyAdmin.test.js | 4 +- .../TransparentUpgradeableProxy.behaviour.js | 22 ++-- .../TransparentUpgradeableProxy.test.js | 4 +- 8 files changed, 132 insertions(+), 59 deletions(-) create mode 100644 .changeset/thirty-shrimps-mix.md create mode 100644 contracts/interfaces/IERC1967.sol diff --git a/.changeset/thirty-shrimps-mix.md b/.changeset/thirty-shrimps-mix.md new file mode 100644 index 000000000..54256d52c --- /dev/null +++ b/.changeset/thirty-shrimps-mix.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': patch +--- + +`TransparentUpgradeableProxy`: Fix transparency in case of selector clash with non-decodable calldata. diff --git a/contracts/interfaces/IERC1967.sol b/contracts/interfaces/IERC1967.sol new file mode 100644 index 000000000..e5deebee9 --- /dev/null +++ b/contracts/interfaces/IERC1967.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC. + * + * _Available since v4.9._ + */ +interface IERC1967 { + /** + * @dev Emitted when the implementation is upgraded. + */ + event Upgraded(address indexed implementation); + + /** + * @dev Emitted when the admin account has changed. + */ + event AdminChanged(address previousAdmin, address newAdmin); + + /** + * @dev Emitted when the beacon is changed. + */ + event BeaconUpgraded(address indexed beacon); +} diff --git a/contracts/proxy/ERC1967/ERC1967Upgrade.sol b/contracts/proxy/ERC1967/ERC1967Upgrade.sol index 0680f3549..a79c10502 100644 --- a/contracts/proxy/ERC1967/ERC1967Upgrade.sol +++ b/contracts/proxy/ERC1967/ERC1967Upgrade.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.2; import "../beacon/IBeacon.sol"; +import "../../interfaces/IERC1967.sol"; import "../../interfaces/draft-IERC1822.sol"; import "../../utils/Address.sol"; import "../../utils/StorageSlot.sol"; @@ -14,7 +15,7 @@ import "../../utils/StorageSlot.sol"; * * _Available since v4.1._ */ -abstract contract ERC1967Upgrade { +abstract contract ERC1967Upgrade is IERC1967 { // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1 bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; @@ -25,11 +26,6 @@ abstract contract ERC1967Upgrade { */ bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; - /** - * @dev Emitted when the implementation is upgraded. - */ - event Upgraded(address indexed implementation); - /** * @dev Returns the current implementation address. */ @@ -95,11 +91,6 @@ abstract contract ERC1967Upgrade { */ bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; - /** - * @dev Emitted when the admin account has changed. - */ - event AdminChanged(address previousAdmin, address newAdmin); - /** * @dev Returns the current admin. */ @@ -131,11 +122,6 @@ abstract contract ERC1967Upgrade { */ bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; - /** - * @dev Emitted when the beacon is upgraded. - */ - event BeaconUpgraded(address indexed beacon); - /** * @dev Returns the current beacon. */ diff --git a/contracts/proxy/transparent/ProxyAdmin.sol b/contracts/proxy/transparent/ProxyAdmin.sol index 839534298..1a9698196 100644 --- a/contracts/proxy/transparent/ProxyAdmin.sol +++ b/contracts/proxy/transparent/ProxyAdmin.sol @@ -18,7 +18,7 @@ contract ProxyAdmin is Ownable { * * - This contract must be the admin of `proxy`. */ - function getProxyImplementation(TransparentUpgradeableProxy proxy) public view virtual returns (address) { + function getProxyImplementation(ITransparentUpgradeableProxy proxy) public view virtual returns (address) { // We need to manually run the static call since the getter cannot be flagged as view // bytes4(keccak256("implementation()")) == 0x5c60da1b (bool success, bytes memory returndata) = address(proxy).staticcall(hex"5c60da1b"); @@ -33,7 +33,7 @@ contract ProxyAdmin is Ownable { * * - This contract must be the admin of `proxy`. */ - function getProxyAdmin(TransparentUpgradeableProxy proxy) public view virtual returns (address) { + function getProxyAdmin(ITransparentUpgradeableProxy proxy) public view virtual returns (address) { // We need to manually run the static call since the getter cannot be flagged as view // bytes4(keccak256("admin()")) == 0xf851a440 (bool success, bytes memory returndata) = address(proxy).staticcall(hex"f851a440"); @@ -48,7 +48,7 @@ contract ProxyAdmin is Ownable { * * - This contract must be the current admin of `proxy`. */ - function changeProxyAdmin(TransparentUpgradeableProxy proxy, address newAdmin) public virtual onlyOwner { + function changeProxyAdmin(ITransparentUpgradeableProxy proxy, address newAdmin) public virtual onlyOwner { proxy.changeAdmin(newAdmin); } @@ -59,7 +59,7 @@ contract ProxyAdmin is Ownable { * * - This contract must be the admin of `proxy`. */ - function upgrade(TransparentUpgradeableProxy proxy, address implementation) public virtual onlyOwner { + function upgrade(ITransparentUpgradeableProxy proxy, address implementation) public virtual onlyOwner { proxy.upgradeTo(implementation); } @@ -72,7 +72,7 @@ contract ProxyAdmin is Ownable { * - This contract must be the admin of `proxy`. */ function upgradeAndCall( - TransparentUpgradeableProxy proxy, + ITransparentUpgradeableProxy proxy, address implementation, bytes memory data ) public payable virtual onlyOwner { diff --git a/contracts/proxy/transparent/TransparentUpgradeableProxy.sol b/contracts/proxy/transparent/TransparentUpgradeableProxy.sol index 155a22e01..a89b233f2 100644 --- a/contracts/proxy/transparent/TransparentUpgradeableProxy.sol +++ b/contracts/proxy/transparent/TransparentUpgradeableProxy.sol @@ -5,6 +5,24 @@ pragma solidity ^0.8.0; import "../ERC1967/ERC1967Proxy.sol"; +/** + * @dev Interface for the {TransparentUpgradeableProxy}. This is useful because {TransparentUpgradeableProxy} uses a + * custom call-routing mechanism, the compiler is unaware of the functions being exposed, and cannot list them. Also + * {TransparentUpgradeableProxy} does not inherit from this interface because it's implemented in a way that the + * compiler doesn't understand and cannot verify. + */ +interface ITransparentUpgradeableProxy is IERC1967 { + function admin() external view returns (address); + + function implementation() external view returns (address); + + function changeAdmin(address) external; + + function upgradeTo(address) external; + + function upgradeToAndCall(address, bytes memory) external payable; +} + /** * @dev This contract implements a proxy that is upgradeable by an admin. * @@ -25,6 +43,13 @@ import "../ERC1967/ERC1967Proxy.sol"; * * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way, * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy. + * + * WARNING: This contract does not inherit from {ITransparentUpgradeableProxy}, and the admin function is implicitly + * implemented using a custom call-routing mechanism in `_fallback`. Consequently, the compiler will not produce an + * ABI for this contract. Also, if you inherit from this contract and add additional functions, the compiler will not + * check that there are no selector conflicts. A selector clash between any new function and the functions declared in + * {ITransparentUpgradeableProxy} will be resolved in favor of the new one. This could render the admin operations + * inaccessible, which could prevent upgradeability. */ contract TransparentUpgradeableProxy is ERC1967Proxy { /** @@ -37,6 +62,9 @@ contract TransparentUpgradeableProxy is ERC1967Proxy { /** * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin. + * + * CAUTION: This modifier is deprecated, as it could cause issues if the modified function has arguments, and the + * implementation provides a function with the same selector. */ modifier ifAdmin() { if (msg.sender == _getAdmin()) { @@ -46,65 +74,98 @@ contract TransparentUpgradeableProxy is ERC1967Proxy { } } + /** + * @dev If caller is the admin process the call internally, otherwise transparently fallback to the proxy behavior + */ + function _fallback() internal virtual override { + if (msg.sender == _getAdmin()) { + bytes memory ret; + bytes4 selector = msg.sig; + if (selector == ITransparentUpgradeableProxy.upgradeTo.selector) { + ret = _dispatchUpgradeTo(); + } else if (selector == ITransparentUpgradeableProxy.upgradeToAndCall.selector) { + ret = _dispatchUpgradeToAndCall(); + } else if (selector == ITransparentUpgradeableProxy.changeAdmin.selector) { + ret = _dispatchChangeAdmin(); + } else if (selector == ITransparentUpgradeableProxy.admin.selector) { + ret = _dispatchAdmin(); + } else if (selector == ITransparentUpgradeableProxy.implementation.selector) { + ret = _dispatchImplementation(); + } else { + revert("TransparentUpgradeableProxy: admin cannot fallback to proxy target"); + } + assembly { + return(add(ret, 0x20), mload(ret)) + } + } else { + super._fallback(); + } + } + /** * @dev Returns the current admin. * - * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}. - * * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103` */ - function admin() external payable ifAdmin returns (address admin_) { + function _dispatchAdmin() private returns (bytes memory) { _requireZeroValue(); - admin_ = _getAdmin(); + + address admin = _getAdmin(); + return abi.encode(admin); } /** * @dev Returns the current implementation. * - * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}. - * * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc` */ - function implementation() external payable ifAdmin returns (address implementation_) { + function _dispatchImplementation() private returns (bytes memory) { _requireZeroValue(); - implementation_ = _implementation(); + + address implementation = _implementation(); + return abi.encode(implementation); } /** * @dev Changes the admin of the proxy. * * Emits an {AdminChanged} event. - * - * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}. */ - function changeAdmin(address newAdmin) external payable virtual ifAdmin { + function _dispatchChangeAdmin() private returns (bytes memory) { _requireZeroValue(); + + address newAdmin = abi.decode(msg.data[4:], (address)); _changeAdmin(newAdmin); + + return ""; } /** * @dev Upgrade the implementation of the proxy. - * - * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}. */ - function upgradeTo(address newImplementation) external payable ifAdmin { + function _dispatchUpgradeTo() private returns (bytes memory) { _requireZeroValue(); + + address newImplementation = abi.decode(msg.data[4:], (address)); _upgradeToAndCall(newImplementation, bytes(""), false); + + return ""; } /** * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the * proxied contract. - * - * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}. */ - function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin { + function _dispatchUpgradeToAndCall() private returns (bytes memory) { + (address newImplementation, bytes memory data) = abi.decode(msg.data[4:], (address, bytes)); _upgradeToAndCall(newImplementation, data, true); + + return ""; } /** @@ -114,14 +175,6 @@ contract TransparentUpgradeableProxy is ERC1967Proxy { return _getAdmin(); } - /** - * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}. - */ - function _beforeFallback() internal virtual override { - require(msg.sender != _getAdmin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target"); - super._beforeFallback(); - } - /** * @dev To keep this contract fully transparent, all `ifAdmin` functions must be payable. This helper is here to * emulate some proxy functions being non-payable while still allowing value to pass through. diff --git a/test/proxy/transparent/ProxyAdmin.test.js b/test/proxy/transparent/ProxyAdmin.test.js index 811dc5671..6d473d893 100644 --- a/test/proxy/transparent/ProxyAdmin.test.js +++ b/test/proxy/transparent/ProxyAdmin.test.js @@ -6,6 +6,7 @@ const ImplV1 = artifacts.require('DummyImplementation'); const ImplV2 = artifacts.require('DummyImplementationV2'); const ProxyAdmin = artifacts.require('ProxyAdmin'); const TransparentUpgradeableProxy = artifacts.require('TransparentUpgradeableProxy'); +const ITransparentUpgradeableProxy = artifacts.require('ITransparentUpgradeableProxy'); contract('ProxyAdmin', function (accounts) { const [proxyAdminOwner, newAdmin, anotherAccount] = accounts; @@ -18,12 +19,13 @@ contract('ProxyAdmin', function (accounts) { beforeEach(async function () { const initializeData = Buffer.from(''); this.proxyAdmin = await ProxyAdmin.new({ from: proxyAdminOwner }); - this.proxy = await TransparentUpgradeableProxy.new( + const proxy = await TransparentUpgradeableProxy.new( this.implementationV1.address, this.proxyAdmin.address, initializeData, { from: proxyAdminOwner }, ); + this.proxy = await ITransparentUpgradeableProxy.at(proxy.address); }); it('has an owner', async function () { diff --git a/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js b/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js index 3a10357a9..66c0a406c 100644 --- a/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js +++ b/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js @@ -34,7 +34,7 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy(createProx describe('implementation', function () { it('returns the current implementation address', async function () { - const implementation = await this.proxy.implementation.call({ from: proxyAdminAddress }); + const implementation = await this.proxy.implementation({ from: proxyAdminAddress }); expect(implementation).to.be.equal(this.implementationV0); }); @@ -55,7 +55,7 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy(createProx it('upgrades to the requested implementation', async function () { await this.proxy.upgradeTo(this.implementationV1, { from }); - const implementation = await this.proxy.implementation.call({ from: proxyAdminAddress }); + const implementation = await this.proxy.implementation({ from: proxyAdminAddress }); expect(implementation).to.be.equal(this.implementationV1); }); @@ -103,7 +103,7 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy(createProx }); it('upgrades to the requested implementation', async function () { - const implementation = await this.proxy.implementation.call({ from: proxyAdminAddress }); + const implementation = await this.proxy.implementation({ from: proxyAdminAddress }); expect(implementation).to.be.equal(this.behavior.address); }); @@ -168,7 +168,7 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy(createProx }); it('upgrades to the requested version and emits an event', async function () { - const implementation = await this.proxy.implementation.call({ from: proxyAdminAddress }); + const implementation = await this.proxy.implementation({ from: proxyAdminAddress }); expect(implementation).to.be.equal(this.behaviorV1.address); expectEvent(this.receipt, 'Upgraded', { implementation: this.behaviorV1.address }); }); @@ -196,7 +196,7 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy(createProx }); it('upgrades to the requested version and emits an event', async function () { - const implementation = await this.proxy.implementation.call({ from: proxyAdminAddress }); + const implementation = await this.proxy.implementation({ from: proxyAdminAddress }); expect(implementation).to.be.equal(this.behaviorV2.address); expectEvent(this.receipt, 'Upgraded', { implementation: this.behaviorV2.address }); }); @@ -227,7 +227,7 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy(createProx }); it('upgrades to the requested version and emits an event', async function () { - const implementation = await this.proxy.implementation.call({ from: proxyAdminAddress }); + const implementation = await this.proxy.implementation({ from: proxyAdminAddress }); expect(implementation).to.be.equal(this.behaviorV3.address); expectEvent(this.receipt, 'Upgraded', { implementation: this.behaviorV3.address }); }); @@ -271,7 +271,7 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy(createProx }); it('assigns new proxy admin', async function () { - const newProxyAdmin = await this.proxy.admin.call({ from: newAdmin }); + const newProxyAdmin = await this.proxy.admin({ from: newAdmin }); expect(newProxyAdmin).to.be.equal(anotherAccount); }); @@ -332,21 +332,21 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy(createProx describe('when function names clash', function () { it('when sender is proxy admin should run the proxy function', async function () { - const value = await this.proxy.admin.call({ from: proxyAdminAddress, value: 0 }); + const value = await this.proxy.admin({ from: proxyAdminAddress, value: 0 }); expect(value).to.be.equal(proxyAdminAddress); }); it('when sender is other should delegate to implementation', async function () { - const value = await this.proxy.admin.call({ from: anotherAccount, value: 0 }); + const value = await this.proxy.admin({ from: anotherAccount, value: 0 }); expect(value).to.be.equal('0x0000000000000000000000000000000011111142'); }); it('when sender is proxy admin value should not be accepted', async function () { - await expectRevert.unspecified(this.proxy.admin.call({ from: proxyAdminAddress, value: 1 })); + await expectRevert.unspecified(this.proxy.admin({ from: proxyAdminAddress, value: 1 })); }); it('when sender is other value should be accepted', async function () { - const value = await this.proxy.admin.call({ from: anotherAccount, value: 1 }); + const value = await this.proxy.admin({ from: anotherAccount, value: 1 }); expect(value).to.be.equal('0x0000000000000000000000000000000011111142'); }); }); diff --git a/test/proxy/transparent/TransparentUpgradeableProxy.test.js b/test/proxy/transparent/TransparentUpgradeableProxy.test.js index 86dd55d32..d60a31a21 100644 --- a/test/proxy/transparent/TransparentUpgradeableProxy.test.js +++ b/test/proxy/transparent/TransparentUpgradeableProxy.test.js @@ -2,12 +2,14 @@ const shouldBehaveLikeProxy = require('../Proxy.behaviour'); const shouldBehaveLikeTransparentUpgradeableProxy = require('./TransparentUpgradeableProxy.behaviour'); const TransparentUpgradeableProxy = artifacts.require('TransparentUpgradeableProxy'); +const ITransparentUpgradeableProxy = artifacts.require('ITransparentUpgradeableProxy'); contract('TransparentUpgradeableProxy', function (accounts) { const [proxyAdminAddress, proxyAdminOwner] = accounts; const createProxy = async function (logic, admin, initData, opts) { - return TransparentUpgradeableProxy.new(logic, admin, initData, opts); + const { address } = await TransparentUpgradeableProxy.new(logic, admin, initData, opts); + return ITransparentUpgradeableProxy.at(address); }; shouldBehaveLikeProxy(createProxy, proxyAdminAddress, proxyAdminOwner); From 31723ed608878c2e30710a9c46b51d529c0ba958 Mon Sep 17 00:00:00 2001 From: Renan Souza Date: Wed, 5 Apr 2023 15:47:18 -0300 Subject: [PATCH 091/133] Reenable skipped TransparentUpgradeableProxy test (#4161) Co-authored-by: Francisco --- .../TransparentUpgradeableProxy.behaviour.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js b/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js index 66c0a406c..5e3f561d5 100644 --- a/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js +++ b/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js @@ -3,8 +3,8 @@ const { ZERO_ADDRESS } = constants; const { getSlot, ImplementationSlot, AdminSlot } = require('../../helpers/erc1967'); const { expect } = require('chai'); +const { web3 } = require('hardhat'); -const Proxy = artifacts.require('Proxy'); const Implementation1 = artifacts.require('Implementation1'); const Implementation2 = artifacts.require('Implementation2'); const Implementation3 = artifacts.require('Implementation3'); @@ -122,13 +122,11 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy(createProx expect(balance.toString()).to.be.bignumber.equal(value.toString()); }); - it.skip('uses the storage of the proxy', async function () { + it('uses the storage of the proxy', async function () { // storage layout should look as follows: - // - 0: Initializable storage - // - 1-50: Initailizable reserved storage (50 slots) - // - 51: initializerRan - // - 52: x - const storedValue = await Proxy.at(this.proxyAddress).getStorageAt(52); + // - 0: Initializable storage ++ initializerRan ++ onlyInitializingRan + // - 1: x + const storedValue = await web3.eth.getStorageAt(this.proxyAddress, 1); expect(parseInt(storedValue)).to.eq(42); }); }); From cf86fd9962701396457e50ab0d6cc78aa29a5ebc Mon Sep 17 00:00:00 2001 From: Francisco Date: Wed, 5 Apr 2023 17:20:34 -0300 Subject: [PATCH 092/133] Merge changesets for transparency improvements (#4165) --- .changeset/many-panthers-hide.md | 5 ----- .changeset/thirty-shrimps-mix.md | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) delete mode 100644 .changeset/many-panthers-hide.md diff --git a/.changeset/many-panthers-hide.md b/.changeset/many-panthers-hide.md deleted file mode 100644 index 5f04c99df..000000000 --- a/.changeset/many-panthers-hide.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'openzeppelin-solidity': minor ---- - -`TransparentUpgradeableProxy`: support value passthrough for all ifAdmin function. diff --git a/.changeset/thirty-shrimps-mix.md b/.changeset/thirty-shrimps-mix.md index 54256d52c..656edbf92 100644 --- a/.changeset/thirty-shrimps-mix.md +++ b/.changeset/thirty-shrimps-mix.md @@ -2,4 +2,4 @@ 'openzeppelin-solidity': patch --- -`TransparentUpgradeableProxy`: Fix transparency in case of selector clash with non-decodable calldata. +`TransparentUpgradeableProxy`: Fix transparency in case of selector clash with non-decodable calldata or payable mutability. From f2346b6749546707af883e2c0acbc8a487e16ae4 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Tue, 11 Apr 2023 11:21:53 +0200 Subject: [PATCH 093/133] Add fuzz tests for the Checkpoints library (#4146) Co-authored-by: Francisco --- scripts/generate/run.js | 28 +- scripts/generate/templates/Checkpoints.js | 23 +- .../generate/templates/Checkpoints.opts.js | 22 ++ scripts/generate/templates/Checkpoints.t.js | 252 +++++++++++++ test/utils/Checkpoints.t.sol | 341 ++++++++++++++++++ 5 files changed, 636 insertions(+), 30 deletions(-) create mode 100644 scripts/generate/templates/Checkpoints.opts.js create mode 100644 scripts/generate/templates/Checkpoints.t.js create mode 100644 test/utils/Checkpoints.t.sol diff --git a/scripts/generate/run.js b/scripts/generate/run.js index e68681e9d..368b53ad1 100755 --- a/scripts/generate/run.js +++ b/scripts/generate/run.js @@ -13,16 +13,10 @@ function getVersion(path) { } } -for (const [file, template] of Object.entries({ - 'utils/math/SafeCast.sol': './templates/SafeCast.js', - 'utils/structs/EnumerableSet.sol': './templates/EnumerableSet.js', - 'utils/structs/EnumerableMap.sol': './templates/EnumerableMap.js', - 'utils/Checkpoints.sol': './templates/Checkpoints.js', - 'utils/StorageSlot.sol': './templates/StorageSlot.js', -})) { +function generateFromTemplate(file, template, outputPrefix = '') { const script = path.relative(path.join(__dirname, '../..'), __filename); const input = path.join(path.dirname(script), template); - const output = `./contracts/${file}`; + const output = path.join(outputPrefix, file); const version = getVersion(output); const content = format( '// SPDX-License-Identifier: MIT', @@ -35,3 +29,21 @@ for (const [file, template] of Object.entries({ fs.writeFileSync(output, content); cp.execFileSync('prettier', ['--write', output]); } + +// Contracts +for (const [file, template] of Object.entries({ + 'utils/math/SafeCast.sol': './templates/SafeCast.js', + 'utils/structs/EnumerableSet.sol': './templates/EnumerableSet.js', + 'utils/structs/EnumerableMap.sol': './templates/EnumerableMap.js', + 'utils/Checkpoints.sol': './templates/Checkpoints.js', + 'utils/StorageSlot.sol': './templates/StorageSlot.js', +})) { + generateFromTemplate(file, template, './contracts/'); +} + +// Tests +for (const [file, template] of Object.entries({ + 'utils/Checkpoints.t.sol': './templates/Checkpoints.t.js', +})) { + generateFromTemplate(file, template, './test/'); +} diff --git a/scripts/generate/templates/Checkpoints.js b/scripts/generate/templates/Checkpoints.js index e51e8b8d1..18999682d 100644 --- a/scripts/generate/templates/Checkpoints.js +++ b/scripts/generate/templates/Checkpoints.js @@ -1,26 +1,5 @@ const format = require('../format-lines'); - -// OPTIONS -const defaultOpts = size => ({ - historyTypeName: `Trace${size}`, - checkpointTypeName: `Checkpoint${size}`, - checkpointFieldName: '_checkpoints', - keyTypeName: `uint${256 - size}`, - keyFieldName: '_key', - valueTypeName: `uint${size}`, - valueFieldName: '_value', -}); - -const VALUE_SIZES = [224, 160]; - -const OPTS = VALUE_SIZES.map(size => defaultOpts(size)); - -const LEGACY_OPTS = { - ...defaultOpts(224), - historyTypeName: 'History', - checkpointTypeName: 'Checkpoint', - keyFieldName: '_blockNumber', -}; +const { OPTS, LEGACY_OPTS } = require('./Checkpoints.opts.js'); // TEMPLATE const header = `\ diff --git a/scripts/generate/templates/Checkpoints.opts.js b/scripts/generate/templates/Checkpoints.opts.js new file mode 100644 index 000000000..03c5a9569 --- /dev/null +++ b/scripts/generate/templates/Checkpoints.opts.js @@ -0,0 +1,22 @@ +// OPTIONS +const VALUE_SIZES = [224, 160]; + +const defaultOpts = size => ({ + historyTypeName: `Trace${size}`, + checkpointTypeName: `Checkpoint${size}`, + checkpointFieldName: '_checkpoints', + keyTypeName: `uint${256 - size}`, + keyFieldName: '_key', + valueTypeName: `uint${size}`, + valueFieldName: '_value', +}); + +module.exports = { + OPTS: VALUE_SIZES.map(size => defaultOpts(size)), + LEGACY_OPTS: { + ...defaultOpts(224), + historyTypeName: 'History', + checkpointTypeName: 'Checkpoint', + keyFieldName: '_blockNumber', + }, +}; diff --git a/scripts/generate/templates/Checkpoints.t.js b/scripts/generate/templates/Checkpoints.t.js new file mode 100644 index 000000000..84b5992ad --- /dev/null +++ b/scripts/generate/templates/Checkpoints.t.js @@ -0,0 +1,252 @@ +const format = require('../format-lines'); +const { capitalize } = require('../../helpers'); +const { OPTS, LEGACY_OPTS } = require('./Checkpoints.opts.js'); + +// TEMPLATE +const header = `\ +pragma solidity ^0.8.0; + +import "forge-std/Test.sol"; +import "../../contracts/utils/Checkpoints.sol"; +import "../../contracts/utils/math/SafeCast.sol"; +`; + +/* eslint-disable max-len */ +const common = opts => `\ +using Checkpoints for Checkpoints.${opts.historyTypeName}; + +// Maximum gap between keys used during the fuzzing tests: the \`_prepareKeys\` function with make sure that +// key#n+1 is in the [key#n, key#n + _KEY_MAX_GAP] range. +uint8 internal constant _KEY_MAX_GAP = 64; + +Checkpoints.${opts.historyTypeName} internal _ckpts; + +// helpers +function _bound${capitalize(opts.keyTypeName)}( + ${opts.keyTypeName} x, + ${opts.keyTypeName} min, + ${opts.keyTypeName} max +) internal view returns (${opts.keyTypeName}) { + return SafeCast.to${capitalize(opts.keyTypeName)}(bound(uint256(x), uint256(min), uint256(max))); +} + +function _prepareKeys( + ${opts.keyTypeName}[] memory keys, + ${opts.keyTypeName} maxSpread +) internal view { + ${opts.keyTypeName} lastKey = 0; + for (uint256 i = 0; i < keys.length; ++i) { + ${opts.keyTypeName} key = _bound${capitalize(opts.keyTypeName)}(keys[i], lastKey, lastKey + maxSpread); + keys[i] = key; + lastKey = key; + } +} + +function _assertLatestCheckpoint( + bool exist, + ${opts.keyTypeName} key, + ${opts.valueTypeName} value +) internal { + (bool _exist, ${opts.keyTypeName} _key, ${opts.valueTypeName} _value) = _ckpts.latestCheckpoint(); + assertEq(_exist, exist); + assertEq(_key, key); + assertEq(_value, value); +} +`; + +const testTrace = opts => `\ +// tests +function testPush( + ${opts.keyTypeName}[] memory keys, + ${opts.valueTypeName}[] memory values, + ${opts.keyTypeName} pastKey +) public { + vm.assume(values.length > 0 && values.length <= keys.length); + _prepareKeys(keys, _KEY_MAX_GAP); + + // initial state + assertEq(_ckpts.length(), 0); + assertEq(_ckpts.latest(), 0); + _assertLatestCheckpoint(false, 0, 0); + + uint256 duplicates = 0; + for (uint256 i = 0; i < keys.length; ++i) { + ${opts.keyTypeName} key = keys[i]; + ${opts.valueTypeName} value = values[i % values.length]; + if (i > 0 && key == keys[i-1]) ++duplicates; + + // push + _ckpts.push(key, value); + + // check length & latest + assertEq(_ckpts.length(), i + 1 - duplicates); + assertEq(_ckpts.latest(), value); + _assertLatestCheckpoint(true, key, value); + } + + if (keys.length > 0) { + ${opts.keyTypeName} lastKey = keys[keys.length - 1]; + pastKey = _bound${capitalize(opts.keyTypeName)}(pastKey, 0, lastKey - 1); + + vm.expectRevert(); + this.push(pastKey, values[keys.length % values.length]); + } +} + +// used to test reverts +function push(${opts.keyTypeName} key, ${opts.valueTypeName} value) external { + _ckpts.push(key, value); +} + +function testLookup( + ${opts.keyTypeName}[] memory keys, + ${opts.valueTypeName}[] memory values, + ${opts.keyTypeName} lookup +) public { + vm.assume(values.length > 0 && values.length <= keys.length); + _prepareKeys(keys, _KEY_MAX_GAP); + + ${opts.keyTypeName} lastKey = keys.length == 0 ? 0 : keys[keys.length - 1]; + lookup = _bound${capitalize(opts.keyTypeName)}(lookup, 0, lastKey + _KEY_MAX_GAP); + + ${opts.valueTypeName} upper = 0; + ${opts.valueTypeName} lower = 0; + ${opts.keyTypeName} lowerKey = type(${opts.keyTypeName}).max; + for (uint256 i = 0; i < keys.length; ++i) { + ${opts.keyTypeName} key = keys[i]; + ${opts.valueTypeName} value = values[i % values.length]; + + // push + _ckpts.push(key, value); + + // track expected result of lookups + if (key <= lookup) { + upper = value; + } + // find the first key that is not smaller than the lookup key + if (key >= lookup && (i == 0 || keys[i-1] < lookup)) { + lowerKey = key; + } + if (key == lowerKey) { + lower = value; + } + } + + // check lookup + assertEq(_ckpts.lowerLookup(lookup), lower); + assertEq(_ckpts.upperLookup(lookup), upper); + assertEq(_ckpts.upperLookupRecent(lookup), upper); +} +`; + +const testHistory = opts => `\ +// tests +function testPush( + ${opts.keyTypeName}[] memory keys, + ${opts.valueTypeName}[] memory values, + ${opts.keyTypeName} pastKey +) public { + vm.assume(values.length > 0 && values.length <= keys.length); + _prepareKeys(keys, _KEY_MAX_GAP); + + // initial state + assertEq(_ckpts.length(), 0); + assertEq(_ckpts.latest(), 0); + _assertLatestCheckpoint(false, 0, 0); + + uint256 duplicates = 0; + for (uint256 i = 0; i < keys.length; ++i) { + ${opts.keyTypeName} key = keys[i]; + ${opts.valueTypeName} value = values[i % values.length]; + if (i > 0 && key == keys[i - 1]) ++duplicates; + + // push + vm.roll(key); + _ckpts.push(value); + + // check length & latest + assertEq(_ckpts.length(), i + 1 - duplicates); + assertEq(_ckpts.latest(), value); + _assertLatestCheckpoint(true, key, value); + } + + // Can't push any key in the past + if (keys.length > 0) { + ${opts.keyTypeName} lastKey = keys[keys.length - 1]; + pastKey = _bound${capitalize(opts.keyTypeName)}(pastKey, 0, lastKey - 1); + + vm.roll(pastKey); + vm.expectRevert(); + this.push(values[keys.length % values.length]); + } +} + +// used to test reverts +function push(${opts.valueTypeName} value) external { + _ckpts.push(value); +} + +function testLookup( + ${opts.keyTypeName}[] memory keys, + ${opts.valueTypeName}[] memory values, + ${opts.keyTypeName} lookup +) public { + vm.assume(keys.length > 0); + vm.assume(values.length > 0 && values.length <= keys.length); + _prepareKeys(keys, _KEY_MAX_GAP); + + ${opts.keyTypeName} lastKey = keys[keys.length - 1]; + vm.assume(lastKey > 0); + lookup = _bound${capitalize(opts.keyTypeName)}(lookup, 0, lastKey - 1); + + ${opts.valueTypeName} upper = 0; + for (uint256 i = 0; i < keys.length; ++i) { + ${opts.keyTypeName} key = keys[i]; + ${opts.valueTypeName} value = values[i % values.length]; + + // push + vm.roll(key); + _ckpts.push(value); + + // track expected result of lookups + if (key <= lookup) { + upper = value; + } + } + + // check lookup + assertEq(_ckpts.getAtBlock(lookup), upper); + assertEq(_ckpts.getAtProbablyRecentBlock(lookup), upper); + + vm.expectRevert(); this.getAtBlock(lastKey); + vm.expectRevert(); this.getAtBlock(lastKey + 1); + vm.expectRevert(); this.getAtProbablyRecentBlock(lastKey); + vm.expectRevert(); this.getAtProbablyRecentBlock(lastKey + 1); +} + +// used to test reverts +function getAtBlock(${opts.keyTypeName} key) external view { + _ckpts.getAtBlock(key); +} + +// used to test reverts +function getAtProbablyRecentBlock(${opts.keyTypeName} key) external view { + _ckpts.getAtProbablyRecentBlock(key); +} +`; +/* eslint-enable max-len */ + +// GENERATE +module.exports = format( + header, + // HISTORY + `contract Checkpoints${LEGACY_OPTS.historyTypeName}Test is Test {`, + [common(LEGACY_OPTS), testHistory(LEGACY_OPTS)], + '}', + // TRACEXXX + ...OPTS.flatMap(opts => [ + `contract Checkpoints${opts.historyTypeName}Test is Test {`, + [common(opts), testTrace(opts)], + '}', + ]), +); diff --git a/test/utils/Checkpoints.t.sol b/test/utils/Checkpoints.t.sol new file mode 100644 index 000000000..abdf8b436 --- /dev/null +++ b/test/utils/Checkpoints.t.sol @@ -0,0 +1,341 @@ +// SPDX-License-Identifier: MIT +// This file was procedurally generated from scripts/generate/templates/Checkpoints.t.js. + +pragma solidity ^0.8.0; + +import "forge-std/Test.sol"; +import "../../contracts/utils/Checkpoints.sol"; +import "../../contracts/utils/math/SafeCast.sol"; + +contract CheckpointsHistoryTest is Test { + using Checkpoints for Checkpoints.History; + + // Maximum gap between keys used during the fuzzing tests: the `_prepareKeys` function with make sure that + // key#n+1 is in the [key#n, key#n + _KEY_MAX_GAP] range. + uint8 internal constant _KEY_MAX_GAP = 64; + + Checkpoints.History internal _ckpts; + + // helpers + function _boundUint32(uint32 x, uint32 min, uint32 max) internal view returns (uint32) { + return SafeCast.toUint32(bound(uint256(x), uint256(min), uint256(max))); + } + + function _prepareKeys(uint32[] memory keys, uint32 maxSpread) internal view { + uint32 lastKey = 0; + for (uint256 i = 0; i < keys.length; ++i) { + uint32 key = _boundUint32(keys[i], lastKey, lastKey + maxSpread); + keys[i] = key; + lastKey = key; + } + } + + function _assertLatestCheckpoint(bool exist, uint32 key, uint224 value) internal { + (bool _exist, uint32 _key, uint224 _value) = _ckpts.latestCheckpoint(); + assertEq(_exist, exist); + assertEq(_key, key); + assertEq(_value, value); + } + + // tests + function testPush(uint32[] memory keys, uint224[] memory values, uint32 pastKey) public { + vm.assume(values.length > 0 && values.length <= keys.length); + _prepareKeys(keys, _KEY_MAX_GAP); + + // initial state + assertEq(_ckpts.length(), 0); + assertEq(_ckpts.latest(), 0); + _assertLatestCheckpoint(false, 0, 0); + + uint256 duplicates = 0; + for (uint256 i = 0; i < keys.length; ++i) { + uint32 key = keys[i]; + uint224 value = values[i % values.length]; + if (i > 0 && key == keys[i - 1]) ++duplicates; + + // push + vm.roll(key); + _ckpts.push(value); + + // check length & latest + assertEq(_ckpts.length(), i + 1 - duplicates); + assertEq(_ckpts.latest(), value); + _assertLatestCheckpoint(true, key, value); + } + + // Can't push any key in the past + if (keys.length > 0) { + uint32 lastKey = keys[keys.length - 1]; + pastKey = _boundUint32(pastKey, 0, lastKey - 1); + + vm.roll(pastKey); + vm.expectRevert(); + this.push(values[keys.length % values.length]); + } + } + + // used to test reverts + function push(uint224 value) external { + _ckpts.push(value); + } + + function testLookup(uint32[] memory keys, uint224[] memory values, uint32 lookup) public { + vm.assume(keys.length > 0); + vm.assume(values.length > 0 && values.length <= keys.length); + _prepareKeys(keys, _KEY_MAX_GAP); + + uint32 lastKey = keys[keys.length - 1]; + vm.assume(lastKey > 0); + lookup = _boundUint32(lookup, 0, lastKey - 1); + + uint224 upper = 0; + for (uint256 i = 0; i < keys.length; ++i) { + uint32 key = keys[i]; + uint224 value = values[i % values.length]; + + // push + vm.roll(key); + _ckpts.push(value); + + // track expected result of lookups + if (key <= lookup) { + upper = value; + } + } + + // check lookup + assertEq(_ckpts.getAtBlock(lookup), upper); + assertEq(_ckpts.getAtProbablyRecentBlock(lookup), upper); + + vm.expectRevert(); + this.getAtBlock(lastKey); + vm.expectRevert(); + this.getAtBlock(lastKey + 1); + vm.expectRevert(); + this.getAtProbablyRecentBlock(lastKey); + vm.expectRevert(); + this.getAtProbablyRecentBlock(lastKey + 1); + } + + // used to test reverts + function getAtBlock(uint32 key) external view { + _ckpts.getAtBlock(key); + } + + // used to test reverts + function getAtProbablyRecentBlock(uint32 key) external view { + _ckpts.getAtProbablyRecentBlock(key); + } +} + +contract CheckpointsTrace224Test is Test { + using Checkpoints for Checkpoints.Trace224; + + // Maximum gap between keys used during the fuzzing tests: the `_prepareKeys` function with make sure that + // key#n+1 is in the [key#n, key#n + _KEY_MAX_GAP] range. + uint8 internal constant _KEY_MAX_GAP = 64; + + Checkpoints.Trace224 internal _ckpts; + + // helpers + function _boundUint32(uint32 x, uint32 min, uint32 max) internal view returns (uint32) { + return SafeCast.toUint32(bound(uint256(x), uint256(min), uint256(max))); + } + + function _prepareKeys(uint32[] memory keys, uint32 maxSpread) internal view { + uint32 lastKey = 0; + for (uint256 i = 0; i < keys.length; ++i) { + uint32 key = _boundUint32(keys[i], lastKey, lastKey + maxSpread); + keys[i] = key; + lastKey = key; + } + } + + function _assertLatestCheckpoint(bool exist, uint32 key, uint224 value) internal { + (bool _exist, uint32 _key, uint224 _value) = _ckpts.latestCheckpoint(); + assertEq(_exist, exist); + assertEq(_key, key); + assertEq(_value, value); + } + + // tests + function testPush(uint32[] memory keys, uint224[] memory values, uint32 pastKey) public { + vm.assume(values.length > 0 && values.length <= keys.length); + _prepareKeys(keys, _KEY_MAX_GAP); + + // initial state + assertEq(_ckpts.length(), 0); + assertEq(_ckpts.latest(), 0); + _assertLatestCheckpoint(false, 0, 0); + + uint256 duplicates = 0; + for (uint256 i = 0; i < keys.length; ++i) { + uint32 key = keys[i]; + uint224 value = values[i % values.length]; + if (i > 0 && key == keys[i - 1]) ++duplicates; + + // push + _ckpts.push(key, value); + + // check length & latest + assertEq(_ckpts.length(), i + 1 - duplicates); + assertEq(_ckpts.latest(), value); + _assertLatestCheckpoint(true, key, value); + } + + if (keys.length > 0) { + uint32 lastKey = keys[keys.length - 1]; + pastKey = _boundUint32(pastKey, 0, lastKey - 1); + + vm.expectRevert(); + this.push(pastKey, values[keys.length % values.length]); + } + } + + // used to test reverts + function push(uint32 key, uint224 value) external { + _ckpts.push(key, value); + } + + function testLookup(uint32[] memory keys, uint224[] memory values, uint32 lookup) public { + vm.assume(values.length > 0 && values.length <= keys.length); + _prepareKeys(keys, _KEY_MAX_GAP); + + uint32 lastKey = keys.length == 0 ? 0 : keys[keys.length - 1]; + lookup = _boundUint32(lookup, 0, lastKey + _KEY_MAX_GAP); + + uint224 upper = 0; + uint224 lower = 0; + uint32 lowerKey = type(uint32).max; + for (uint256 i = 0; i < keys.length; ++i) { + uint32 key = keys[i]; + uint224 value = values[i % values.length]; + + // push + _ckpts.push(key, value); + + // track expected result of lookups + if (key <= lookup) { + upper = value; + } + // find the first key that is not smaller than the lookup key + if (key >= lookup && (i == 0 || keys[i - 1] < lookup)) { + lowerKey = key; + } + if (key == lowerKey) { + lower = value; + } + } + + // check lookup + assertEq(_ckpts.lowerLookup(lookup), lower); + assertEq(_ckpts.upperLookup(lookup), upper); + assertEq(_ckpts.upperLookupRecent(lookup), upper); + } +} + +contract CheckpointsTrace160Test is Test { + using Checkpoints for Checkpoints.Trace160; + + // Maximum gap between keys used during the fuzzing tests: the `_prepareKeys` function with make sure that + // key#n+1 is in the [key#n, key#n + _KEY_MAX_GAP] range. + uint8 internal constant _KEY_MAX_GAP = 64; + + Checkpoints.Trace160 internal _ckpts; + + // helpers + function _boundUint96(uint96 x, uint96 min, uint96 max) internal view returns (uint96) { + return SafeCast.toUint96(bound(uint256(x), uint256(min), uint256(max))); + } + + function _prepareKeys(uint96[] memory keys, uint96 maxSpread) internal view { + uint96 lastKey = 0; + for (uint256 i = 0; i < keys.length; ++i) { + uint96 key = _boundUint96(keys[i], lastKey, lastKey + maxSpread); + keys[i] = key; + lastKey = key; + } + } + + function _assertLatestCheckpoint(bool exist, uint96 key, uint160 value) internal { + (bool _exist, uint96 _key, uint160 _value) = _ckpts.latestCheckpoint(); + assertEq(_exist, exist); + assertEq(_key, key); + assertEq(_value, value); + } + + // tests + function testPush(uint96[] memory keys, uint160[] memory values, uint96 pastKey) public { + vm.assume(values.length > 0 && values.length <= keys.length); + _prepareKeys(keys, _KEY_MAX_GAP); + + // initial state + assertEq(_ckpts.length(), 0); + assertEq(_ckpts.latest(), 0); + _assertLatestCheckpoint(false, 0, 0); + + uint256 duplicates = 0; + for (uint256 i = 0; i < keys.length; ++i) { + uint96 key = keys[i]; + uint160 value = values[i % values.length]; + if (i > 0 && key == keys[i - 1]) ++duplicates; + + // push + _ckpts.push(key, value); + + // check length & latest + assertEq(_ckpts.length(), i + 1 - duplicates); + assertEq(_ckpts.latest(), value); + _assertLatestCheckpoint(true, key, value); + } + + if (keys.length > 0) { + uint96 lastKey = keys[keys.length - 1]; + pastKey = _boundUint96(pastKey, 0, lastKey - 1); + + vm.expectRevert(); + this.push(pastKey, values[keys.length % values.length]); + } + } + + // used to test reverts + function push(uint96 key, uint160 value) external { + _ckpts.push(key, value); + } + + function testLookup(uint96[] memory keys, uint160[] memory values, uint96 lookup) public { + vm.assume(values.length > 0 && values.length <= keys.length); + _prepareKeys(keys, _KEY_MAX_GAP); + + uint96 lastKey = keys.length == 0 ? 0 : keys[keys.length - 1]; + lookup = _boundUint96(lookup, 0, lastKey + _KEY_MAX_GAP); + + uint160 upper = 0; + uint160 lower = 0; + uint96 lowerKey = type(uint96).max; + for (uint256 i = 0; i < keys.length; ++i) { + uint96 key = keys[i]; + uint160 value = values[i % values.length]; + + // push + _ckpts.push(key, value); + + // track expected result of lookups + if (key <= lookup) { + upper = value; + } + // find the first key that is not smaller than the lookup key + if (key >= lookup && (i == 0 || keys[i - 1] < lookup)) { + lowerKey = key; + } + if (key == lowerKey) { + lower = value; + } + } + + // check lookup + assertEq(_ckpts.lowerLookup(lookup), lower); + assertEq(_ckpts.upperLookup(lookup), upper); + assertEq(_ckpts.upperLookupRecent(lookup), upper); + } +} From 473d0b6884ce538f534a0fc04c97b78e8cc0f48b Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Tue, 11 Apr 2023 20:36:58 -0300 Subject: [PATCH 094/133] Add Codecov token --- .github/workflows/checks.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 290c6a943..c6b42dd82 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -73,6 +73,8 @@ jobs: env: NODE_OPTIONS: --max_old_space_size=4096 - uses: codecov/codecov-action@v3 + with: + token: ${{ secrets.CODECOV_TOKEN }} slither: if: github.repository != 'OpenZeppelin/openzeppelin-contracts-upgradeable' From 661343f74ca798c0ac5037411fe39d8ef15f3377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Garc=C3=ADa?= Date: Wed, 12 Apr 2023 04:17:10 +0200 Subject: [PATCH 095/133] Add DoubleEndedQueue FV (#4147) Co-authored-by: Francisco Co-authored-by: Hadrien Croubois --- certora/harnesses/DoubleEndedQueueHarness.sol | 59 +++ certora/specs.json | 5 + certora/specs/DoubleEndedQueue.spec | 366 ++++++++++++++++++ 3 files changed, 430 insertions(+) create mode 100644 certora/harnesses/DoubleEndedQueueHarness.sol create mode 100644 certora/specs/DoubleEndedQueue.spec diff --git a/certora/harnesses/DoubleEndedQueueHarness.sol b/certora/harnesses/DoubleEndedQueueHarness.sol new file mode 100644 index 000000000..b4f0bc841 --- /dev/null +++ b/certora/harnesses/DoubleEndedQueueHarness.sol @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../patched/utils/structs/DoubleEndedQueue.sol"; + +contract DoubleEndedQueueHarness { + using DoubleEndedQueue for DoubleEndedQueue.Bytes32Deque; + + DoubleEndedQueue.Bytes32Deque private _deque; + + function pushFront(bytes32 value) external { + _deque.pushFront(value); + } + + function pushBack(bytes32 value) external { + _deque.pushBack(value); + } + + function popFront() external returns (bytes32 value) { + return _deque.popFront(); + } + + function popBack() external returns (bytes32 value) { + return _deque.popBack(); + } + + function clear() external { + _deque.clear(); + } + + function begin() external view returns (int128) { + return _deque._begin; + } + + function end() external view returns (int128) { + return _deque._end; + } + + function length() external view returns (uint256) { + return _deque.length(); + } + + function empty() external view returns (bool) { + return _deque.empty(); + } + + function front() external view returns (bytes32 value) { + return _deque.front(); + } + + function back() external view returns (bytes32 value) { + return _deque.back(); + } + + function at_(uint256 index) external view returns (bytes32 value) { + return _deque.at(index); + } +} diff --git a/certora/specs.json b/certora/specs.json index 80fbf26af..cd68af65e 100644 --- a/certora/specs.json +++ b/certora/specs.json @@ -9,6 +9,11 @@ "contract": "AccessControlHarness", "files": ["certora/harnesses/AccessControlHarness.sol"] }, + { + "spec": "DoubleEndedQueue", + "contract": "DoubleEndedQueueHarness", + "files": ["certora/harnesses/DoubleEndedQueueHarness.sol"] + }, { "spec": "Ownable", "contract": "OwnableHarness", diff --git a/certora/specs/DoubleEndedQueue.spec b/certora/specs/DoubleEndedQueue.spec new file mode 100644 index 000000000..2412b4cc8 --- /dev/null +++ b/certora/specs/DoubleEndedQueue.spec @@ -0,0 +1,366 @@ +import "helpers.spec" + +methods { + pushFront(bytes32) envfree + pushBack(bytes32) envfree + popFront() returns (bytes32) envfree + popBack() returns (bytes32) envfree + clear() envfree + + // exposed for FV + begin() returns (int128) envfree + end() returns (int128) envfree + + // view + length() returns (uint256) envfree + empty() returns (bool) envfree + front() returns (bytes32) envfree + back() returns (bytes32) envfree + at_(uint256) returns (bytes32) envfree // at is a reserved word +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Helpers │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ + +function min_int128() returns mathint { + return -(1 << 127); +} + +function max_int128() returns mathint { + return (1 << 127) - 1; +} + +// Could be broken in theory, but not in practice +function boundedQueue() returns bool { + return + max_int128() > to_mathint(end()) && + min_int128() < to_mathint(begin()); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: end is larger or equal than begin │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant boundariesConsistency() + end() >= begin() + filtered { f -> !f.isView } + { preserved { require boundedQueue(); } } + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: length is end minus begin │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant lengthConsistency() + length() == to_mathint(end()) - to_mathint(begin()) + filtered { f -> !f.isView } + { preserved { require boundedQueue(); } } + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: empty() is length 0 and no element exists │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant emptiness() + empty() <=> length() == 0 + filtered { f -> !f.isView } + { preserved { require boundedQueue(); } } + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: front points to the first index and back points to the last one │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant queueEndings() + at_(length() - 1) == back() && at_(0) == front() + filtered { f -> !f.isView } + { + preserved { + requireInvariant boundariesConsistency(); + require boundedQueue(); + } + } + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: pushFront adds an element at the beginning of the queue │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule pushFront(bytes32 value) { + require boundedQueue(); + + uint256 lengthBefore = length(); + + pushFront@withrevert(value); + + // liveness + assert !lastReverted, "never reverts"; + + // effect + assert front() == value, "front set to value"; + assert length() == lengthBefore + 1, "queue extended"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: pushFront preserves the previous values in the queue with a +1 offset │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule pushFrontConsistency(uint256 index) { + require boundedQueue(); + + bytes32 beforeAt = at_(index); + + bytes32 value; + pushFront(value); + + // try to read value + bytes32 afterAt = at_@withrevert(index + 1); + + assert !lastReverted, "value still there"; + assert afterAt == beforeAt, "data is preserved"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: pushBack adds an element at the end of the queue │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule pushBack(bytes32 value) { + require boundedQueue(); + + uint256 lengthBefore = length(); + + pushBack@withrevert(value); + + // liveness + assert !lastReverted, "never reverts"; + + // effect + assert back() == value, "back set to value"; + assert length() == lengthBefore + 1, "queue increased"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: pushBack preserves the previous values in the queue │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule pushBackConsistency(uint256 index) { + require boundedQueue(); + + bytes32 beforeAt = at_(index); + + bytes32 value; + pushBack(value); + + // try to read value + bytes32 afterAt = at_@withrevert(index); + + assert !lastReverted, "value still there"; + assert afterAt == beforeAt, "data is preserved"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: popFront removes an element from the beginning of the queue │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule popFront { + requireInvariant boundariesConsistency(); + require boundedQueue(); + + uint256 lengthBefore = length(); + bytes32 frontBefore = front@withrevert(); + + bytes32 popped = popFront@withrevert(); + bool success = !lastReverted; + + // liveness + assert success <=> lengthBefore != 0, "never reverts if not previously empty"; + + // effect + assert success => frontBefore == popped, "previous front is returned"; + assert success => length() == lengthBefore - 1, "queue decreased"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: at(x) is preserved and offset to at(x - 1) after calling popFront | +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule popFrontConsistency(uint256 index) { + requireInvariant boundariesConsistency(); + require boundedQueue(); + + // Read (any) value that is not the front (this asserts the value exists / the queue is long enough) + require index > 1; + bytes32 before = at_(index); + + popFront(); + + // try to read value + bytes32 after = at_@withrevert(index - 1); + + assert !lastReverted, "value still exists in the queue"; + assert before == after, "values are offset and not modified"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: popBack removes an element from the end of the queue │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule popBack { + requireInvariant boundariesConsistency(); + require boundedQueue(); + + uint256 lengthBefore = length(); + bytes32 backBefore = back@withrevert(); + + bytes32 popped = popBack@withrevert(); + bool success = !lastReverted; + + // liveness + assert success <=> lengthBefore != 0, "never reverts if not previously empty"; + + // effect + assert success => backBefore == popped, "previous back is returned"; + assert success => length() == lengthBefore - 1, "queue decreased"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: at(x) is preserved after calling popBack | +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule popBackConsistency(uint256 index) { + requireInvariant boundariesConsistency(); + require boundedQueue(); + + // Read (any) value that is not the back (this asserts the value exists / the queue is long enough) + require index < length() - 1; + bytes32 before = at_(index); + + popBack(); + + // try to read value + bytes32 after = at_@withrevert(index); + + assert !lastReverted, "value still exists in the queue"; + assert before == after, "values are offset and not modified"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: clear sets length to 0 │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule clear { + clear@withrevert(); + + // liveness + assert !lastReverted, "never reverts"; + + // effect + assert length() == 0, "sets length to 0"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: front/back access reverts only if the queue is empty or querying out of bounds │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule onlyEmptyRevert(env e) { + require nonpayable(e); + requireInvariant boundariesConsistency(); + require boundedQueue(); + + method f; + calldataarg args; + + bool emptyBefore = empty(); + + f@withrevert(e, args); + + assert lastReverted => ( + (f.selector == front().selector && emptyBefore) || + (f.selector == back().selector && emptyBefore) || + (f.selector == popFront().selector && emptyBefore) || + (f.selector == popBack().selector && emptyBefore) || + f.selector == at_(uint256).selector // revert conditions are verified in onlyOutOfBoundsRevert + ), "only revert if empty or out of bounds"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: at(index) only reverts if index is out of bounds | +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule onlyOutOfBoundsRevert(uint256 index) { + requireInvariant boundariesConsistency(); + require boundedQueue(); + + at_@withrevert(index); + + assert lastReverted <=> index >= length(), "only reverts if index is out of bounds"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: only clear/push/pop operations can change the length of the queue │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule noLengthChange(env e) { + requireInvariant boundariesConsistency(); + require boundedQueue(); + + method f; + calldataarg args; + + uint256 lengthBefore = length(); + f(e, args); + uint256 lengthAfter = length(); + + assert lengthAfter != lengthBefore => ( + (f.selector == pushFront(bytes32).selector && lengthAfter == lengthBefore + 1) || + (f.selector == pushBack(bytes32).selector && lengthAfter == lengthBefore + 1) || + (f.selector == popBack().selector && lengthAfter == lengthBefore - 1) || + (f.selector == popFront().selector && lengthAfter == lengthBefore - 1) || + (f.selector == clear().selector && lengthAfter == 0) + ), "length is only affected by clear/pop/push operations"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: only push/pop can change values bounded in the queue (outside values aren't cleared) │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule noDataChange(env e) { + requireInvariant boundariesConsistency(); + require boundedQueue(); + + method f; + calldataarg args; + + uint256 index; + bytes32 atBefore = at_(index); + f(e, args); + bytes32 atAfter = at_@withrevert(index); + bool atAfterSuccess = !lastReverted; + + assert !atAfterSuccess <=> ( + f.selector == clear().selector || + (f.selector == popBack().selector && index == length()) || + (f.selector == popFront().selector && index == length()) + ), "indexes of the queue are only removed by clear or pop"; + + assert atAfterSuccess && atAfter != atBefore => ( + f.selector == popFront().selector || + f.selector == pushFront(bytes32).selector + ), "values of the queue are only changed by popFront or pushFront"; +} From 86f6eb2c9c0eb741de18ef75a290ff340acf7148 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Wed, 12 Apr 2023 05:29:36 +0200 Subject: [PATCH 096/133] Add FV specification for ERC721 (#4104) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ernesto García --- certora/diff/token_ERC721_ERC721.sol.patch | 14 + certora/harnesses/ERC721Harness.sol | 37 ++ certora/harnesses/ERC721ReceiverHarness.sol | 11 + certora/specs.json | 6 + certora/specs/ERC721.spec | 589 ++++++++++++++++++++ certora/specs/methods/IERC721.spec | 20 + 6 files changed, 677 insertions(+) create mode 100644 certora/diff/token_ERC721_ERC721.sol.patch create mode 100644 certora/harnesses/ERC721Harness.sol create mode 100644 certora/harnesses/ERC721ReceiverHarness.sol create mode 100644 certora/specs/ERC721.spec create mode 100644 certora/specs/methods/IERC721.spec diff --git a/certora/diff/token_ERC721_ERC721.sol.patch b/certora/diff/token_ERC721_ERC721.sol.patch new file mode 100644 index 000000000..c3eae357a --- /dev/null +++ b/certora/diff/token_ERC721_ERC721.sol.patch @@ -0,0 +1,14 @@ +--- token/ERC721/ERC721.sol 2023-03-07 10:48:47.736822221 +0100 ++++ token/ERC721/ERC721.sol 2023-03-09 19:49:39.669338673 +0100 +@@ -199,6 +199,11 @@ + return _owners[tokenId]; + } + ++ // FV ++ function _getApproved(uint256 tokenId) internal view returns (address) { ++ return _tokenApprovals[tokenId]; ++ } ++ + /** + * @dev Returns whether `tokenId` exists. + * diff --git a/certora/harnesses/ERC721Harness.sol b/certora/harnesses/ERC721Harness.sol new file mode 100644 index 000000000..3307369a8 --- /dev/null +++ b/certora/harnesses/ERC721Harness.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../patched/token/ERC721/ERC721.sol"; + +contract ERC721Harness is ERC721 { + constructor(string memory name, string memory symbol) ERC721(name, symbol) {} + + function mint(address account, uint256 tokenId) external { + _mint(account, tokenId); + } + + function safeMint(address to, uint256 tokenId) external { + _safeMint(to, tokenId); + } + + function safeMint(address to, uint256 tokenId, bytes memory data) external { + _safeMint(to, tokenId, data); + } + + function burn(uint256 tokenId) external { + _burn(tokenId); + } + + function tokenExists(uint256 tokenId) external view returns (bool) { + return _exists(tokenId); + } + + function unsafeOwnerOf(uint256 tokenId) external view returns (address) { + return _ownerOf(tokenId); + } + + function unsafeGetApproved(uint256 tokenId) external view returns (address) { + return _getApproved(tokenId); + } +} diff --git a/certora/harnesses/ERC721ReceiverHarness.sol b/certora/harnesses/ERC721ReceiverHarness.sol new file mode 100644 index 000000000..7e5739ee3 --- /dev/null +++ b/certora/harnesses/ERC721ReceiverHarness.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../patched/interfaces/IERC721Receiver.sol"; + +contract ERC721ReceiverHarness is IERC721Receiver { + function onERC721Received(address, address, uint256, bytes calldata) external pure returns (bytes4) { + return this.onERC721Received.selector; + } +} diff --git a/certora/specs.json b/certora/specs.json index cd68af65e..39ba8c235 100644 --- a/certora/specs.json +++ b/certora/specs.json @@ -51,6 +51,12 @@ "--optimistic_loop" ] }, + { + "spec": "ERC721", + "contract": "ERC721Harness", + "files": ["certora/harnesses/ERC721Harness.sol", "certora/harnesses/ERC721ReceiverHarness.sol"], + "options": ["--optimistic_loop"] + }, { "spec": "Initializable", "contract": "InitializableHarness", diff --git a/certora/specs/ERC721.spec b/certora/specs/ERC721.spec new file mode 100644 index 000000000..48503469b --- /dev/null +++ b/certora/specs/ERC721.spec @@ -0,0 +1,589 @@ +import "helpers.spec" +import "methods/IERC721.spec" + +methods { + // exposed for FV + mint(address,uint256) + safeMint(address,uint256) + safeMint(address,uint256,bytes) + burn(uint256) + + tokenExists(uint256) returns (bool) envfree + unsafeOwnerOf(uint256) returns (address) envfree + unsafeGetApproved(uint256) returns (address) envfree +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Helpers │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ + +// Could be broken in theory, but not in practice +function balanceLimited(address account) returns bool { + return balanceOf(account) < max_uint256; +} + +function helperTransferWithRevert(env e, method f, address from, address to, uint256 tokenId) { + if (f.selector == transferFrom(address,address,uint256).selector) { + transferFrom@withrevert(e, from, to, tokenId); + } else if (f.selector == safeTransferFrom(address,address,uint256).selector) { + safeTransferFrom@withrevert(e, from, to, tokenId); + } else if (f.selector == safeTransferFrom(address,address,uint256,bytes).selector) { + bytes params; + require params.length < 0xffff; + safeTransferFrom@withrevert(e, from, to, tokenId, params); + } else { + calldataarg args; + f@withrevert(e, args); + } +} + +function helperMintWithRevert(env e, method f, address to, uint256 tokenId) { + if (f.selector == mint(address,uint256).selector) { + mint@withrevert(e, to, tokenId); + } else if (f.selector == safeMint(address,uint256).selector) { + safeMint@withrevert(e, to, tokenId); + } else if (f.selector == safeMint(address,uint256,bytes).selector) { + bytes params; + require params.length < 0xffff; + safeMint@withrevert(e, to, tokenId, params); + } else { + require false; + } +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Ghost & hooks: ownership count │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +ghost ownedTotal() returns uint256 { + init_state axiom ownedTotal() == 0; +} + +ghost mapping(address => uint256) ownedByUser { + init_state axiom forall address a. ownedByUser[a] == 0; +} + +hook Sstore _owners[KEY uint256 tokenId] address newOwner (address oldOwner) STORAGE { + ownedByUser[newOwner] = ownedByUser[newOwner] + to_uint256(newOwner != 0 ? 1 : 0); + ownedByUser[oldOwner] = ownedByUser[oldOwner] - to_uint256(oldOwner != 0 ? 1 : 0); + + havoc ownedTotal assuming ownedTotal@new() == ownedTotal@old() + + to_uint256(newOwner != 0 ? 1 : 0) + - to_uint256(oldOwner != 0 ? 1 : 0); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Ghost & hooks: sum of all balances │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +ghost sumOfBalances() returns uint256 { + init_state axiom sumOfBalances() == 0; +} + +hook Sstore _balances[KEY address addr] uint256 newValue (uint256 oldValue) STORAGE { + havoc sumOfBalances assuming sumOfBalances@new() == sumOfBalances@old() + newValue - oldValue; +} + +ghost mapping(address => uint256) ghostBalanceOf { + init_state axiom forall address a. ghostBalanceOf[a] == 0; +} + +hook Sload uint256 value _balances[KEY address user] STORAGE { + require ghostBalanceOf[user] == value; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: ownedTotal is the sum of all balances │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant ownedTotalIsSumOfBalances() + ownedTotal() == sumOfBalances() + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: balanceOf is the number of tokens owned │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant balanceOfConsistency(address user) + balanceOf(user) == ownedByUser[user] && + balanceOf(user) == ghostBalanceOf[user] + { + preserved { + require balanceLimited(user); + } + } + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: owner of a token must have some balance │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant ownerHasBalance(uint256 tokenId) + balanceOf(ownerOf(tokenId)) > 0 + { + preserved { + requireInvariant balanceOfConsistency(ownerOf(tokenId)); + require balanceLimited(ownerOf(tokenId)); + } + } + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: tokens that do not exist are not owned and not approved │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant notMintedUnset(uint256 tokenId) + (!tokenExists(tokenId) <=> unsafeOwnerOf(tokenId) == 0) && + (!tokenExists(tokenId) => unsafeGetApproved(tokenId) == 0) + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: ownerOf and getApproved revert if token does not exist │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule notMintedRevert(uint256 tokenId) { + requireInvariant notMintedUnset(tokenId); + + bool e = tokenExists(tokenId); + + address owner = ownerOf@withrevert(tokenId); + assert e <=> !lastReverted; + assert e => owner == unsafeOwnerOf(tokenId); // notMintedUnset tells us this is non-zero + + address approved = getApproved@withrevert(tokenId); + assert e <=> !lastReverted; + assert e => approved == unsafeGetApproved(tokenId); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: unsafeOwnerOf and unsafeGetApproved don't revert │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule unsafeDontRevert(uint256 tokenId) { + unsafeOwnerOf@withrevert(tokenId); + assert !lastReverted; + + unsafeGetApproved@withrevert(tokenId); + assert !lastReverted; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: balance of address(0) is 0 │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule zeroAddressBalanceRevert() { + balanceOf@withrevert(0); + assert lastReverted; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rules: total supply can only change through mint and burn │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule supplyChange(env e) { + uint256 supplyBefore = ownedTotal(); + method f; calldataarg args; f(e, args); + uint256 supplyAfter = ownedTotal(); + + assert supplyAfter > supplyBefore => ( + supplyAfter == supplyBefore + 1 && + ( + f.selector == mint(address,uint256).selector || + f.selector == safeMint(address,uint256).selector || + f.selector == safeMint(address,uint256,bytes).selector + ) + ); + assert supplyAfter < supplyBefore => ( + supplyAfter == supplyBefore - 1 && + f.selector == burn(uint256).selector + ); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rules: balanceOf can only change through mint, burn or transfers. balanceOf cannot change by more than 1. │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule balanceChange(env e, address account) { + requireInvariant balanceOfConsistency(account); + require balanceLimited(account); + + uint256 balanceBefore = balanceOf(account); + method f; calldataarg args; f(e, args); + uint256 balanceAfter = balanceOf(account); + + // balance can change by at most 1 + assert balanceBefore != balanceAfter => ( + balanceAfter == balanceBefore - 1 || + balanceAfter == balanceBefore + 1 + ); + + // only selected function can change balances + assert balanceBefore != balanceAfter => ( + f.selector == transferFrom(address,address,uint256).selector || + f.selector == safeTransferFrom(address,address,uint256).selector || + f.selector == safeTransferFrom(address,address,uint256,bytes).selector || + f.selector == mint(address,uint256).selector || + f.selector == safeMint(address,uint256).selector || + f.selector == safeMint(address,uint256,bytes).selector || + f.selector == burn(uint256).selector + ); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rules: ownership can only change through mint, burn or transfers. │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule ownershipChange(env e, uint256 tokenId) { + address ownerBefore = unsafeOwnerOf(tokenId); + method f; calldataarg args; f(e, args); + address ownerAfter = unsafeOwnerOf(tokenId); + + assert ownerBefore == 0 && ownerAfter != 0 => ( + f.selector == mint(address,uint256).selector || + f.selector == safeMint(address,uint256).selector || + f.selector == safeMint(address,uint256,bytes).selector + ); + + assert ownerBefore != 0 && ownerAfter == 0 => ( + f.selector == burn(uint256).selector + ); + + assert (ownerBefore != ownerAfter && ownerBefore != 0 && ownerAfter != 0) => ( + f.selector == transferFrom(address,address,uint256).selector || + f.selector == safeTransferFrom(address,address,uint256).selector || + f.selector == safeTransferFrom(address,address,uint256,bytes).selector + ); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rules: token approval can only change through approve or transfers (implicitly). │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule approvalChange(env e, uint256 tokenId) { + address approvalBefore = unsafeGetApproved(tokenId); + method f; calldataarg args; f(e, args); + address approvalAfter = unsafeGetApproved(tokenId); + + // approve can set any value, other functions reset + assert approvalBefore != approvalAfter => ( + f.selector == approve(address,uint256).selector || + ( + ( + f.selector == transferFrom(address,address,uint256).selector || + f.selector == safeTransferFrom(address,address,uint256).selector || + f.selector == safeTransferFrom(address,address,uint256,bytes).selector || + f.selector == burn(uint256).selector + ) && approvalAfter == 0 + ) + ); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rules: approval for all tokens can only change through isApprovedForAll. │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule approvedForAllChange(env e, address owner, address spender) { + bool approvedForAllBefore = isApprovedForAll(owner, spender); + method f; calldataarg args; f(e, args); + bool approvedForAllAfter = isApprovedForAll(owner, spender); + + assert approvedForAllBefore != approvedForAllAfter => f.selector == setApprovalForAll(address,bool).selector; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: transferFrom behavior and side effects │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule transferFrom(env e, address from, address to, uint256 tokenId) { + require nonpayable(e); + + address operator = e.msg.sender; + uint256 otherTokenId; + address otherAccount; + + requireInvariant ownerHasBalance(tokenId); + require balanceLimited(to); + + uint256 balanceOfFromBefore = balanceOf(from); + uint256 balanceOfToBefore = balanceOf(to); + uint256 balanceOfOtherBefore = balanceOf(otherAccount); + address ownerBefore = unsafeOwnerOf(tokenId); + address otherOwnerBefore = unsafeOwnerOf(otherTokenId); + address approvalBefore = unsafeGetApproved(tokenId); + address otherApprovalBefore = unsafeGetApproved(otherTokenId); + + transferFrom@withrevert(e, from, to, tokenId); + bool success = !lastReverted; + + // liveness + assert success <=> ( + from == ownerBefore && + from != 0 && + to != 0 && + (operator == from || operator == approvalBefore || isApprovedForAll(ownerBefore, operator)) + ); + + // effect + assert success => ( + balanceOf(from) == balanceOfFromBefore - to_uint256(from != to ? 1 : 0) && + balanceOf(to) == balanceOfToBefore + to_uint256(from != to ? 1 : 0) && + unsafeOwnerOf(tokenId) == to && + unsafeGetApproved(tokenId) == 0 + ); + + // no side effect + assert balanceOf(otherAccount) != balanceOfOtherBefore => (otherAccount == from || otherAccount == to); + assert unsafeOwnerOf(otherTokenId) != otherOwnerBefore => otherTokenId == tokenId; + assert unsafeGetApproved(otherTokenId) != otherApprovalBefore => otherTokenId == tokenId; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: safeTransferFrom behavior and side effects │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule safeTransferFrom(env e, method f, address from, address to, uint256 tokenId) filtered { f -> + f.selector == safeTransferFrom(address,address,uint256).selector || + f.selector == safeTransferFrom(address,address,uint256,bytes).selector +} { + require nonpayable(e); + + address operator = e.msg.sender; + uint256 otherTokenId; + address otherAccount; + + requireInvariant ownerHasBalance(tokenId); + require balanceLimited(to); + + uint256 balanceOfFromBefore = balanceOf(from); + uint256 balanceOfToBefore = balanceOf(to); + uint256 balanceOfOtherBefore = balanceOf(otherAccount); + address ownerBefore = unsafeOwnerOf(tokenId); + address otherOwnerBefore = unsafeOwnerOf(otherTokenId); + address approvalBefore = unsafeGetApproved(tokenId); + address otherApprovalBefore = unsafeGetApproved(otherTokenId); + + helperTransferWithRevert(e, f, from, to, tokenId); + bool success = !lastReverted; + + assert success <=> ( + from == ownerBefore && + from != 0 && + to != 0 && + (operator == from || operator == approvalBefore || isApprovedForAll(ownerBefore, operator)) + ); + + // effect + assert success => ( + balanceOf(from) == balanceOfFromBefore - to_uint256(from != to ? 1: 0) && + balanceOf(to) == balanceOfToBefore + to_uint256(from != to ? 1: 0) && + unsafeOwnerOf(tokenId) == to && + unsafeGetApproved(tokenId) == 0 + ); + + // no side effect + assert balanceOf(otherAccount) != balanceOfOtherBefore => (otherAccount == from || otherAccount == to); + assert unsafeOwnerOf(otherTokenId) != otherOwnerBefore => otherTokenId == tokenId; + assert unsafeGetApproved(otherTokenId) != otherApprovalBefore => otherTokenId == tokenId; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: mint behavior and side effects │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule mint(env e, address to, uint256 tokenId) { + require nonpayable(e); + requireInvariant notMintedUnset(tokenId); + + uint256 otherTokenId; + address otherAccount; + + require balanceLimited(to); + + uint256 supplyBefore = ownedTotal(); + uint256 balanceOfToBefore = balanceOf(to); + uint256 balanceOfOtherBefore = balanceOf(otherAccount); + address ownerBefore = unsafeOwnerOf(tokenId); + address otherOwnerBefore = unsafeOwnerOf(otherTokenId); + + mint@withrevert(e, to, tokenId); + bool success = !lastReverted; + + // liveness + assert success <=> ( + ownerBefore == 0 && + to != 0 + ); + + // effect + assert success => ( + ownedTotal() == supplyBefore + 1 && + balanceOf(to) == balanceOfToBefore + 1 && + unsafeOwnerOf(tokenId) == to + ); + + // no side effect + assert balanceOf(otherAccount) != balanceOfOtherBefore => otherAccount == to; + assert unsafeOwnerOf(otherTokenId) != otherOwnerBefore => otherTokenId == tokenId; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: safeMint behavior and side effects │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule safeMint(env e, method f, address to, uint256 tokenId) filtered { f -> + f.selector == safeMint(address,uint256).selector || + f.selector == safeMint(address,uint256,bytes).selector +} { + require nonpayable(e); + requireInvariant notMintedUnset(tokenId); + + uint256 otherTokenId; + address otherAccount; + + require balanceLimited(to); + + uint256 supplyBefore = ownedTotal(); + uint256 balanceOfToBefore = balanceOf(to); + uint256 balanceOfOtherBefore = balanceOf(otherAccount); + address ownerBefore = unsafeOwnerOf(tokenId); + address otherOwnerBefore = unsafeOwnerOf(otherTokenId); + + helperMintWithRevert(e, f, to, tokenId); + bool success = !lastReverted; + + assert success <=> ( + ownerBefore == 0 && + to != 0 + ); + + // effect + assert success => ( + ownedTotal() == supplyBefore + 1 && + balanceOf(to) == balanceOfToBefore + 1 && + unsafeOwnerOf(tokenId) == to + ); + + // no side effect + assert balanceOf(otherAccount) != balanceOfOtherBefore => otherAccount == to; + assert unsafeOwnerOf(otherTokenId) != otherOwnerBefore => otherTokenId == tokenId; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: burn behavior and side effects │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule burn(env e, uint256 tokenId) { + require nonpayable(e); + + address from = unsafeOwnerOf(tokenId); + uint256 otherTokenId; + address otherAccount; + + requireInvariant ownerHasBalance(tokenId); + + uint256 supplyBefore = ownedTotal(); + uint256 balanceOfFromBefore = balanceOf(from); + uint256 balanceOfOtherBefore = balanceOf(otherAccount); + address ownerBefore = unsafeOwnerOf(tokenId); + address otherOwnerBefore = unsafeOwnerOf(otherTokenId); + address otherApprovalBefore = unsafeGetApproved(otherTokenId); + + burn@withrevert(e, tokenId); + bool success = !lastReverted; + + // liveness + assert success <=> ( + ownerBefore != 0 + ); + + // effect + assert success => ( + ownedTotal() == supplyBefore - 1 && + balanceOf(from) == balanceOfFromBefore - 1 && + unsafeOwnerOf(tokenId) == 0 && + unsafeGetApproved(tokenId) == 0 + ); + + // no side effect + assert balanceOf(otherAccount) != balanceOfOtherBefore => otherAccount == from; + assert unsafeOwnerOf(otherTokenId) != otherOwnerBefore => otherTokenId == tokenId; + assert unsafeGetApproved(otherTokenId) != otherApprovalBefore => otherTokenId == tokenId; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: approve behavior and side effects │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule approve(env e, address spender, uint256 tokenId) { + require nonpayable(e); + + address caller = e.msg.sender; + address owner = unsafeOwnerOf(tokenId); + uint256 otherTokenId; + + address otherApprovalBefore = unsafeGetApproved(otherTokenId); + + approve@withrevert(e, spender, tokenId); + bool success = !lastReverted; + + // liveness + assert success <=> ( + owner != 0 && + owner != spender && + (owner == caller || isApprovedForAll(owner, caller)) + ); + + // effect + assert success => unsafeGetApproved(tokenId) == spender; + + // no side effect + assert unsafeGetApproved(otherTokenId) != otherApprovalBefore => otherTokenId == tokenId; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: setApprovalForAll behavior and side effects │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule setApprovalForAll(env e, address operator, bool approved) { + require nonpayable(e); + + address owner = e.msg.sender; + address otherOwner; + address otherOperator; + + bool otherIsApprovedForAllBefore = isApprovedForAll(otherOwner, otherOperator); + + setApprovalForAll@withrevert(e, operator, approved); + bool success = !lastReverted; + + // liveness + assert success <=> owner != operator; + + // effect + assert success => isApprovedForAll(owner, operator) == approved; + + // no side effect + assert isApprovedForAll(otherOwner, otherOperator) != otherIsApprovedForAllBefore => ( + otherOwner == owner && + otherOperator == operator + ); +} diff --git a/certora/specs/methods/IERC721.spec b/certora/specs/methods/IERC721.spec new file mode 100644 index 000000000..e6d4e1e04 --- /dev/null +++ b/certora/specs/methods/IERC721.spec @@ -0,0 +1,20 @@ +methods { + // IERC721 + balanceOf(address) returns (uint256) envfree => DISPATCHER(true) + ownerOf(uint256) returns (address) envfree => DISPATCHER(true) + getApproved(uint256) returns (address) envfree => DISPATCHER(true) + isApprovedForAll(address,address) returns (bool) envfree => DISPATCHER(true) + safeTransferFrom(address,address,uint256,bytes) => DISPATCHER(true) + safeTransferFrom(address,address,uint256) => DISPATCHER(true) + transferFrom(address,address,uint256) => DISPATCHER(true) + approve(address,uint256) => DISPATCHER(true) + setApprovalForAll(address,bool) => DISPATCHER(true) + + // IERC721Metadata + name() returns (string) => DISPATCHER(true) + symbol() returns (string) => DISPATCHER(true) + tokenURI(uint256) returns (string) => DISPATCHER(true) + + // IERC721Receiver + onERC721Received(address,address,uint256,bytes) returns (bytes4) => DISPATCHER(true) +} From 788d6a129a342d7a23a91ad553479e861845a9b2 Mon Sep 17 00:00:00 2001 From: Francisco Date: Wed, 12 Apr 2023 12:09:30 -0300 Subject: [PATCH 097/133] Add fuzz tests for ShortString (#4175) --- test/utils/ShortStrings.t.sol | 55 +++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 test/utils/ShortStrings.t.sol diff --git a/test/utils/ShortStrings.t.sol b/test/utils/ShortStrings.t.sol new file mode 100644 index 000000000..7c4faa89d --- /dev/null +++ b/test/utils/ShortStrings.t.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "forge-std/Test.sol"; + +import "../../contracts/utils/ShortStrings.sol"; + +contract ShortStringsTest is Test { + string _fallback; + + function testRoundtripShort(string memory input) external { + vm.assume(_isShort(input)); + ShortString short = ShortStrings.toShortString(input); + string memory output = ShortStrings.toString(short); + assertEq(input, output); + } + + function testRoundtripWithFallback(string memory input, string memory fallbackInitial) external { + _fallback = fallbackInitial; // Make sure that the initial value has no effect + ShortString short = ShortStrings.toShortStringWithFallback(input, _fallback); + string memory output = ShortStrings.toStringWithFallback(short, _fallback); + assertEq(input, output); + } + + function testRevertLong(string memory input) external { + vm.assume(!_isShort(input)); + vm.expectRevert(abi.encodeWithSelector(ShortStrings.StringTooLong.selector, input)); + this.toShortString(input); + } + + function testLengthShort(string memory input) external { + vm.assume(_isShort(input)); + uint256 inputLength = bytes(input).length; + ShortString short = ShortStrings.toShortString(input); + uint256 shortLength = ShortStrings.byteLength(short); + assertEq(inputLength, shortLength); + } + + function testLengthWithFallback(string memory input, string memory fallbackInitial) external { + _fallback = fallbackInitial; + uint256 inputLength = bytes(input).length; + ShortString short = ShortStrings.toShortStringWithFallback(input, _fallback); + uint256 shortLength = ShortStrings.byteLengthWithFallback(short, _fallback); + assertEq(inputLength, shortLength); + } + + function toShortString(string memory input) external pure returns (ShortString) { + return ShortStrings.toShortString(input); + } + + function _isShort(string memory input) internal pure returns (bool) { + return bytes(input).length < 32; + } +} From dd1265cb1dc834b129c6daf6aae7bdae28521d9e Mon Sep 17 00:00:00 2001 From: Pascal Marco Caversaccio Date: Wed, 12 Apr 2023 22:33:50 +0200 Subject: [PATCH 098/133] Improve `ERC4626` test coverage (#4134) Signed-off-by: Pascal Marco Caversaccio --- .../mocks/token/ERC20ExcessDecimalsMock.sol | 9 +++++ remappings.txt | 1 + test/token/ERC20/extensions/ERC4626.t.sol | 34 ++++++++++++++++--- test/token/ERC20/extensions/ERC4626.test.js | 23 +++++++++++++ 4 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 contracts/mocks/token/ERC20ExcessDecimalsMock.sol create mode 100644 remappings.txt diff --git a/contracts/mocks/token/ERC20ExcessDecimalsMock.sol b/contracts/mocks/token/ERC20ExcessDecimalsMock.sol new file mode 100644 index 000000000..0fb35a607 --- /dev/null +++ b/contracts/mocks/token/ERC20ExcessDecimalsMock.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +contract ERC20ExcessDecimalsMock { + function decimals() public pure returns (uint256) { + return type(uint256).max; + } +} diff --git a/remappings.txt b/remappings.txt new file mode 100644 index 000000000..2479e3d26 --- /dev/null +++ b/remappings.txt @@ -0,0 +1 @@ +openzeppelin/=contracts/ diff --git a/test/token/ERC20/extensions/ERC4626.t.sol b/test/token/ERC20/extensions/ERC4626.t.sol index 95514531c..f220086d1 100644 --- a/test/token/ERC20/extensions/ERC4626.t.sol +++ b/test/token/ERC20/extensions/ERC4626.t.sol @@ -1,18 +1,42 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "erc4626-tests/ERC4626.test.sol"; +import {ERC4626Test} from "erc4626-tests/ERC4626.test.sol"; -import {SafeCast} from "../../../../contracts/utils/math/SafeCast.sol"; -import {ERC20Mock} from "../../../../contracts/mocks/ERC20Mock.sol"; -import {ERC4626Mock} from "../../../../contracts/mocks/ERC4626Mock.sol"; +import {SafeCast} from "openzeppelin/utils/math/SafeCast.sol"; +import {ERC20} from "openzeppelin/token/ERC20/ERC20.sol"; +import {ERC4626} from "openzeppelin/token/ERC20/extensions/ERC4626.sol"; + +import {ERC20Mock} from "openzeppelin/mocks/ERC20Mock.sol"; +import {ERC4626Mock} from "openzeppelin/mocks/ERC4626Mock.sol"; +import {ERC4626OffsetMock} from "openzeppelin/mocks/token/ERC4626OffsetMock.sol"; + +contract ERC4626VaultOffsetMock is ERC4626OffsetMock { + constructor( + ERC20 underlying_, + uint8 offset_ + ) ERC20("My Token Vault", "MTKNV") ERC4626(underlying_) ERC4626OffsetMock(offset_) {} +} contract ERC4626StdTest is ERC4626Test { + ERC20 private _underlying = new ERC20Mock(); + function setUp() public override { - _underlying_ = address(new ERC20Mock()); + _underlying_ = address(_underlying); _vault_ = address(new ERC4626Mock(_underlying_)); _delta_ = 0; _vaultMayBeEmpty = true; _unlimitedAmount = true; } + + /** + * @dev Check the case where calculated `decimals` value overflows the `uint8` type. + */ + function testFuzzDecimalsOverflow(uint8 offset) public { + /// @dev Remember that the `_underlying` exhibits a `decimals` value of 18. + offset = uint8(bound(uint256(offset), 238, uint256(type(uint8).max))); + ERC4626VaultOffsetMock erc4626VaultOffsetMock = new ERC4626VaultOffsetMock(_underlying, offset); + vm.expectRevert(); + erc4626VaultOffsetMock.decimals(); + } } diff --git a/test/token/ERC20/extensions/ERC4626.test.js b/test/token/ERC20/extensions/ERC4626.test.js index c9e5a4098..ee0998717 100644 --- a/test/token/ERC20/extensions/ERC4626.test.js +++ b/test/token/ERC20/extensions/ERC4626.test.js @@ -5,6 +5,7 @@ const ERC20Decimals = artifacts.require('$ERC20DecimalsMock'); const ERC4626 = artifacts.require('$ERC4626'); const ERC4626OffsetMock = artifacts.require('$ERC4626OffsetMock'); const ERC4626FeesMock = artifacts.require('$ERC4626FeesMock'); +const ERC20ExcessDecimalsMock = artifacts.require('ERC20ExcessDecimalsMock'); contract('ERC4626', function (accounts) { const [holder, recipient, spender, other, user1, user2] = accounts; @@ -21,6 +22,28 @@ contract('ERC4626', function (accounts) { } }); + it('asset has not yet been created', async function () { + const vault = await ERC4626.new('', '', other); + expect(await vault.decimals()).to.be.bignumber.equal(decimals); + }); + + it('underlying excess decimals', async function () { + const token = await ERC20ExcessDecimalsMock.new(); + const vault = await ERC4626.new('', '', token.address); + expect(await vault.decimals()).to.be.bignumber.equal(decimals); + }); + + it('decimals overflow', async function () { + for (const offset of [243, 250, 255].map(web3.utils.toBN)) { + const token = await ERC20Decimals.new('', '', decimals); + const vault = await ERC4626OffsetMock.new(name + ' Vault', symbol + 'V', token.address, offset); + await expectRevert( + vault.decimals(), + 'reverted with panic code 0x11 (Arithmetic operation underflowed or overflowed outside of an unchecked block)', + ); + } + }); + for (const offset of [0, 6, 18].map(web3.utils.toBN)) { const parseToken = token => web3.utils.toBN(10).pow(decimals).muln(token); const parseShare = share => web3.utils.toBN(10).pow(decimals.add(offset)).muln(share); From 3b117992e17ae67fcd19ea2bd988f64520813cd1 Mon Sep 17 00:00:00 2001 From: Francisco Date: Thu, 13 Apr 2023 11:04:04 -0300 Subject: [PATCH 099/133] Improve docs for transparent proxy (#4181) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ernesto García --- contracts/proxy/README.adoc | 2 ++ .../TransparentUpgradeableProxy.sol | 24 +++++++++++-------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/contracts/proxy/README.adoc b/contracts/proxy/README.adoc index 5ada16e38..89717a7bf 100644 --- a/contracts/proxy/README.adoc +++ b/contracts/proxy/README.adoc @@ -56,6 +56,8 @@ The current implementation of this security mechanism uses https://eips.ethereum == ERC1967 +{{IERC1967}} + {{ERC1967Proxy}} {{ERC1967Upgrade}} diff --git a/contracts/proxy/transparent/TransparentUpgradeableProxy.sol b/contracts/proxy/transparent/TransparentUpgradeableProxy.sol index a89b233f2..d8765fc9e 100644 --- a/contracts/proxy/transparent/TransparentUpgradeableProxy.sol +++ b/contracts/proxy/transparent/TransparentUpgradeableProxy.sol @@ -6,10 +6,10 @@ pragma solidity ^0.8.0; import "../ERC1967/ERC1967Proxy.sol"; /** - * @dev Interface for the {TransparentUpgradeableProxy}. This is useful because {TransparentUpgradeableProxy} uses a - * custom call-routing mechanism, the compiler is unaware of the functions being exposed, and cannot list them. Also - * {TransparentUpgradeableProxy} does not inherit from this interface because it's implemented in a way that the - * compiler doesn't understand and cannot verify. + * @dev Interface for {TransparentUpgradeableProxy}. In order to implement transparency, {TransparentUpgradeableProxy} + * does not implement this interface directly, and some of its functions are implemented by an internal dispatch + * mechanism. The compiler is unaware that these functions are implemented by {TransparentUpgradeableProxy} and will not + * include them in the ABI so this interface must be used to interact with it. */ interface ITransparentUpgradeableProxy is IERC1967 { function admin() external view returns (address); @@ -44,12 +44,16 @@ interface ITransparentUpgradeableProxy is IERC1967 { * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way, * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy. * - * WARNING: This contract does not inherit from {ITransparentUpgradeableProxy}, and the admin function is implicitly - * implemented using a custom call-routing mechanism in `_fallback`. Consequently, the compiler will not produce an - * ABI for this contract. Also, if you inherit from this contract and add additional functions, the compiler will not - * check that there are no selector conflicts. A selector clash between any new function and the functions declared in - * {ITransparentUpgradeableProxy} will be resolved in favor of the new one. This could render the admin operations - * inaccessible, which could prevent upgradeability. + * NOTE: The real interface of this proxy is that defined in `ITransparentUpgradeableProxy`. This contract does not + * inherit from that interface, and instead the admin functions are implicitly implemented using a custom dispatch + * mechanism in `_fallback`. Consequently, the compiler will not produce an ABI for this contract. This is necessary to + * fully implement transparency without decoding reverts caused by selector clashes between the proxy and the + * implementation. + * + * WARNING: It is not recommended to extend this contract to add additional external functions. If you do so, the compiler + * will not check that there are no selector conflicts, due to the note above. A selector clash between any new function + * and the functions declared in {ITransparentUpgradeableProxy} will be resolved in favor of the new one. This could + * render the admin operations inaccessible, which could prevent upgradeability. Transparency may also be compromised. */ contract TransparentUpgradeableProxy is ERC1967Proxy { /** From 8d633cb7d169f2f8595b273660b00b69e845c2fe Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Thu, 13 Apr 2023 20:47:51 +0200 Subject: [PATCH 100/133] Merge pull request from GHSA-93hq-5wgc-jc82 Co-authored-by: Francisco --- .changeset/silent-pugs-scream.md | 5 +++++ .../compatibility/GovernorCompatibilityBravo.sol | 4 ++-- .../GovernorCompatibilityBravo.test.js | 15 +++++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 .changeset/silent-pugs-scream.md diff --git a/.changeset/silent-pugs-scream.md b/.changeset/silent-pugs-scream.md new file mode 100644 index 000000000..c92d12486 --- /dev/null +++ b/.changeset/silent-pugs-scream.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': patch +--- + +`GovernorCompatibilityBravo`: Fix encoding of proposal data when signatures are missing. diff --git a/contracts/governance/compatibility/GovernorCompatibilityBravo.sol b/contracts/governance/compatibility/GovernorCompatibilityBravo.sol index 25f404403..7fd8ce0c4 100644 --- a/contracts/governance/compatibility/GovernorCompatibilityBravo.sol +++ b/contracts/governance/compatibility/GovernorCompatibilityBravo.sol @@ -70,6 +70,7 @@ abstract contract GovernorCompatibilityBravo is IGovernorTimelock, IGovernorComp bytes[] memory calldatas, string memory description ) public virtual override returns (uint256) { + require(signatures.length == calldatas.length, "GovernorBravo: invalid signatures length"); // Stores the full proposal and fallback to the public (possibly overridden) propose. The fallback is done // after the full proposal is stored, so the store operation included in the fallback will be skipped. Here we // call `propose` and not `super.propose` to make sure if a child contract override `propose`, whatever code @@ -149,8 +150,7 @@ abstract contract GovernorCompatibilityBravo is IGovernorTimelock, IGovernorComp bytes[] memory calldatas ) private pure returns (bytes[] memory) { bytes[] memory fullcalldatas = new bytes[](calldatas.length); - - for (uint256 i = 0; i < signatures.length; ++i) { + for (uint256 i = 0; i < fullcalldatas.length; ++i) { fullcalldatas[i] = bytes(signatures[i]).length == 0 ? calldatas[i] : abi.encodePacked(bytes4(keccak256(bytes(signatures[i]))), calldatas[i]); diff --git a/test/governance/compatibility/GovernorCompatibilityBravo.test.js b/test/governance/compatibility/GovernorCompatibilityBravo.test.js index 9e551949f..5a8104a98 100644 --- a/test/governance/compatibility/GovernorCompatibilityBravo.test.js +++ b/test/governance/compatibility/GovernorCompatibilityBravo.test.js @@ -224,6 +224,21 @@ contract('GovernorCompatibilityBravo', function (accounts) { }); }); + it('with inconsistent array size for selector and arguments', async function () { + const target = this.receiver.address; + this.helper.setProposal( + { + targets: [target, target], + values: [0, 0], + signatures: ['mockFunction()'], // One signature + data: ['0x', this.receiver.contract.methods.mockFunctionWithArgs(17, 42).encodeABI()], // Two data entries + }, + '', + ); + + await expectRevert(this.helper.propose({ from: proposer }), 'GovernorBravo: invalid signatures length'); + }); + describe('should revert', function () { describe('on propose', function () { it('if proposal does not meet proposalThreshold', async function () { From 91df66c4a9dfd0425ff923cbeb3a20155f1355ea Mon Sep 17 00:00:00 2001 From: Francisco Date: Fri, 21 Apr 2023 12:35:07 +0100 Subject: [PATCH 101/133] Implement suggestions from audit of 4.9 (#4176) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ernesto García --- contracts/governance/Governor.sol | 54 +++++++++++-------- contracts/governance/IGovernor.sol | 8 ++- contracts/governance/TimelockController.sol | 25 +++++---- .../GovernorCompatibilityBravo.sol | 10 ++-- .../IGovernorCompatibilityBravo.sol | 5 ++ .../extensions/GovernorPreventLateQuorum.sol | 12 ++--- .../extensions/GovernorTimelockCompound.sol | 14 +++-- .../extensions/GovernorTimelockControl.sol | 10 ++-- .../GovernorVotesQuorumFraction.sol | 7 ++- contracts/governance/utils/IVotes.sol | 4 +- contracts/governance/utils/Votes.sol | 6 +-- .../token/ERC20/extensions/ERC20Votes.sol | 2 +- .../token/ERC721/extensions/ERC721Votes.sol | 2 + test/governance/Governor.test.js | 6 +-- .../SupportsInterface.behavior.js | 8 ++- 15 files changed, 97 insertions(+), 76 deletions(-) diff --git a/contracts/governance/Governor.sol b/contracts/governance/Governor.sol index a2911bf98..241d6139b 100644 --- a/contracts/governance/Governor.sol +++ b/contracts/governance/Governor.sol @@ -17,7 +17,7 @@ import "./IGovernor.sol"; /** * @dev Core of the governance system, designed to be extended though various modules. * - * This contract is abstract and requires several function to be implemented in various modules: + * This contract is abstract and requires several functions to be implemented in various modules: * * - A counting module must implement {quorum}, {_quorumReached}, {_voteSucceeded} and {_countVote} * - A voting module must implement {_getVotes} @@ -27,7 +27,6 @@ import "./IGovernor.sol"; */ abstract contract Governor is Context, ERC165, EIP712, IGovernor, IERC721Receiver, IERC1155Receiver { using DoubleEndedQueue for DoubleEndedQueue.Bytes32Deque; - using SafeCast for uint256; bytes32 public constant BALLOT_TYPEHASH = keccak256("Ballot(uint256 proposalId,uint8 support)"); bytes32 public constant EXTENDED_BALLOT_TYPEHASH = @@ -90,25 +89,34 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor, IERC721Receive * @dev Function to receive ETH that will be handled by the governor (disabled if executor is a third party contract) */ receive() external payable virtual { - require(_executor() == address(this)); + require(_executor() == address(this), "Governor: must send to executor"); } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) { - // In addition to the current interfaceId, also support previous version of the interfaceId that did not - // include the castVoteWithReasonAndParams() function as standard + bytes4 governorCancelId = this.cancel.selector ^ this.proposalProposer.selector; + + bytes4 governorParamsId = this.castVoteWithReasonAndParams.selector ^ + this.castVoteWithReasonAndParamsBySig.selector ^ + this.getVotesWithParams.selector; + + // The original interface id in v4.3. + bytes4 governor43Id = type(IGovernor).interfaceId ^ + type(IERC6372).interfaceId ^ + governorCancelId ^ + governorParamsId; + + // An updated interface id in v4.6, with params added. + bytes4 governor46Id = type(IGovernor).interfaceId ^ type(IERC6372).interfaceId ^ governorCancelId; + + // For the updated interface id in v4.9, we use governorCancelId directly. + return - interfaceId == - (type(IGovernor).interfaceId ^ - type(IERC6372).interfaceId ^ - this.cancel.selector ^ - this.castVoteWithReasonAndParams.selector ^ - this.castVoteWithReasonAndParamsBySig.selector ^ - this.getVotesWithParams.selector) || - // Previous interface for backwards compatibility - interfaceId == (type(IGovernor).interfaceId ^ type(IERC6372).interfaceId ^ this.cancel.selector) || + interfaceId == governor43Id || + interfaceId == governor46Id || + interfaceId == governorCancelId || interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId); } @@ -210,9 +218,9 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor, IERC721Receive } /** - * @dev Address of the proposer + * @dev Returns the account that created a given proposal. */ - function _proposalProposer(uint256 proposalId) internal view virtual returns (address) { + function proposalProposer(uint256 proposalId) public view virtual override returns (address) { return _proposals[proposalId].proposer; } @@ -283,8 +291,8 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor, IERC721Receive _proposals[proposalId] = ProposalCore({ proposer: proposer, - voteStart: snapshot.toUint64(), - voteEnd: deadline.toUint64(), + voteStart: SafeCast.toUint64(snapshot), + voteEnd: SafeCast.toUint64(deadline), executed: false, canceled: false, __gap_unused0: 0, @@ -317,9 +325,9 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor, IERC721Receive ) public payable virtual override returns (uint256) { uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash); - ProposalState status = state(proposalId); + ProposalState currentState = state(proposalId); require( - status == ProposalState.Succeeded || status == ProposalState.Queued, + currentState == ProposalState.Succeeded || currentState == ProposalState.Queued, "Governor: proposal not successful" ); _proposals[proposalId].executed = true; @@ -415,10 +423,12 @@ abstract contract Governor is Context, ERC165, EIP712, IGovernor, IERC721Receive ) internal virtual returns (uint256) { uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash); - ProposalState status = state(proposalId); + ProposalState currentState = state(proposalId); require( - status != ProposalState.Canceled && status != ProposalState.Expired && status != ProposalState.Executed, + currentState != ProposalState.Canceled && + currentState != ProposalState.Expired && + currentState != ProposalState.Executed, "Governor: proposal not active" ); _proposals[proposalId].canceled = true; diff --git a/contracts/governance/IGovernor.sol b/contracts/governance/IGovernor.sol index 70f81efe8..e4ad83e87 100644 --- a/contracts/governance/IGovernor.sol +++ b/contracts/governance/IGovernor.sol @@ -152,6 +152,12 @@ abstract contract IGovernor is IERC165, IERC6372 { */ function proposalDeadline(uint256 proposalId) public view virtual returns (uint256); + /** + * @notice module:core + * @dev The account that created a proposal. + */ + function proposalProposer(uint256 proposalId) public view virtual returns (address); + /** * @notice module:user-config * @dev Delay, between the proposal is created and the vote starts. The unit this duration is expressed in depends @@ -164,7 +170,7 @@ abstract contract IGovernor is IERC165, IERC6372 { /** * @notice module:user-config - * @dev Delay, between the vote start and vote ends. The unit this duration is expressed in depends on the clock + * @dev Delay between the vote start and vote end. The unit this duration is expressed in depends on the clock * (see EIP-6372) this contract uses. * * NOTE: The {votingDelay} can delay the start of the vote. This must be considered when setting the voting diff --git a/contracts/governance/TimelockController.sol b/contracts/governance/TimelockController.sol index 18ca81e5f..e330cca06 100644 --- a/contracts/governance/TimelockController.sol +++ b/contracts/governance/TimelockController.sol @@ -6,7 +6,6 @@ pragma solidity ^0.8.0; import "../access/AccessControl.sol"; import "../token/ERC721/IERC721Receiver.sol"; import "../token/ERC1155/IERC1155Receiver.sol"; -import "../utils/Address.sol"; /** * @dev Contract module which acts as a timelocked controller. When set as the @@ -137,21 +136,21 @@ contract TimelockController is AccessControl, IERC721Receiver, IERC1155Receiver * @dev Returns whether an id correspond to a registered operation. This * includes both Pending, Ready and Done operations. */ - function isOperation(bytes32 id) public view virtual returns (bool registered) { + function isOperation(bytes32 id) public view virtual returns (bool) { return getTimestamp(id) > 0; } /** - * @dev Returns whether an operation is pending or not. + * @dev Returns whether an operation is pending or not. Note that a "pending" operation may also be "ready". */ - function isOperationPending(bytes32 id) public view virtual returns (bool pending) { + function isOperationPending(bytes32 id) public view virtual returns (bool) { return getTimestamp(id) > _DONE_TIMESTAMP; } /** - * @dev Returns whether an operation is ready or not. + * @dev Returns whether an operation is ready for execution. Note that a "ready" operation is also "pending". */ - function isOperationReady(bytes32 id) public view virtual returns (bool ready) { + function isOperationReady(bytes32 id) public view virtual returns (bool) { uint256 timestamp = getTimestamp(id); return timestamp > _DONE_TIMESTAMP && timestamp <= block.timestamp; } @@ -159,7 +158,7 @@ contract TimelockController is AccessControl, IERC721Receiver, IERC1155Receiver /** * @dev Returns whether an operation is done or not. */ - function isOperationDone(bytes32 id) public view virtual returns (bool done) { + function isOperationDone(bytes32 id) public view virtual returns (bool) { return getTimestamp(id) == _DONE_TIMESTAMP; } @@ -167,7 +166,7 @@ contract TimelockController is AccessControl, IERC721Receiver, IERC1155Receiver * @dev Returns the timestamp at which an operation becomes ready (0 for * unset operations, 1 for done operations). */ - function getTimestamp(bytes32 id) public view virtual returns (uint256 timestamp) { + function getTimestamp(bytes32 id) public view virtual returns (uint256) { return _timestamps[id]; } @@ -176,7 +175,7 @@ contract TimelockController is AccessControl, IERC721Receiver, IERC1155Receiver * * This value can be changed by executing an operation that calls `updateDelay`. */ - function getMinDelay() public view virtual returns (uint256 duration) { + function getMinDelay() public view virtual returns (uint256) { return _minDelay; } @@ -190,7 +189,7 @@ contract TimelockController is AccessControl, IERC721Receiver, IERC1155Receiver bytes calldata data, bytes32 predecessor, bytes32 salt - ) public pure virtual returns (bytes32 hash) { + ) public pure virtual returns (bytes32) { return keccak256(abi.encode(target, value, data, predecessor, salt)); } @@ -204,14 +203,14 @@ contract TimelockController is AccessControl, IERC721Receiver, IERC1155Receiver bytes[] calldata payloads, bytes32 predecessor, bytes32 salt - ) public pure virtual returns (bytes32 hash) { + ) public pure virtual returns (bytes32) { return keccak256(abi.encode(targets, values, payloads, predecessor, salt)); } /** * @dev Schedule an operation containing a single transaction. * - * Emits events {CallScheduled} and {CallSalt}. + * Emits {CallSalt} if salt is nonzero, and {CallScheduled}. * * Requirements: * @@ -236,7 +235,7 @@ contract TimelockController is AccessControl, IERC721Receiver, IERC1155Receiver /** * @dev Schedule an operation containing a batch of transactions. * - * Emits a {CallSalt} event and one {CallScheduled} event per transaction in the batch. + * Emits {CallSalt} if salt is nonzero, and one {CallScheduled} event per transaction in the batch. * * Requirements: * diff --git a/contracts/governance/compatibility/GovernorCompatibilityBravo.sol b/contracts/governance/compatibility/GovernorCompatibilityBravo.sol index 7fd8ce0c4..0fbb4e17c 100644 --- a/contracts/governance/compatibility/GovernorCompatibilityBravo.sol +++ b/contracts/governance/compatibility/GovernorCompatibilityBravo.sol @@ -74,7 +74,7 @@ abstract contract GovernorCompatibilityBravo is IGovernorTimelock, IGovernorComp // Stores the full proposal and fallback to the public (possibly overridden) propose. The fallback is done // after the full proposal is stored, so the store operation included in the fallback will be skipped. Here we // call `propose` and not `super.propose` to make sure if a child contract override `propose`, whatever code - // is added their is also executed when calling this alternative interface. + // is added there is also executed when calling this alternative interface. _storeProposal(_msgSender(), targets, values, signatures, calldatas, description); return propose(targets, values, _encodeCalldata(signatures, calldatas), description); } @@ -110,7 +110,7 @@ abstract contract GovernorCompatibilityBravo is IGovernorTimelock, IGovernorComp /** * @dev Cancel a proposal with GovernorBravo logic. */ - function cancel(uint256 proposalId) public virtual { + function cancel(uint256 proposalId) public virtual override { ( address[] memory targets, uint256[] memory values, @@ -238,9 +238,9 @@ abstract contract GovernorCompatibilityBravo is IGovernorTimelock, IGovernorComp againstVotes = details.againstVotes; abstainVotes = details.abstainVotes; - ProposalState status = state(proposalId); - canceled = status == ProposalState.Canceled; - executed = status == ProposalState.Executed; + ProposalState currentState = state(proposalId); + canceled = currentState == ProposalState.Canceled; + executed = currentState == ProposalState.Executed; } /** diff --git a/contracts/governance/compatibility/IGovernorCompatibilityBravo.sol b/contracts/governance/compatibility/IGovernorCompatibilityBravo.sol index 159c55100..7aa806a18 100644 --- a/contracts/governance/compatibility/IGovernorCompatibilityBravo.sol +++ b/contracts/governance/compatibility/IGovernorCompatibilityBravo.sol @@ -90,6 +90,11 @@ abstract contract IGovernorCompatibilityBravo is IGovernor { */ function execute(uint256 proposalId) public payable virtual; + /** + * @dev Cancels a proposal only if the sender is the proposer or the proposer delegates' voting power dropped below the proposal threshold. + */ + function cancel(uint256 proposalId) public virtual; + /** * @dev Part of the Governor Bravo's interface: _"Gets actions of a proposal"_. */ diff --git a/contracts/governance/extensions/GovernorPreventLateQuorum.sol b/contracts/governance/extensions/GovernorPreventLateQuorum.sol index 676d2b13e..68496ca1e 100644 --- a/contracts/governance/extensions/GovernorPreventLateQuorum.sol +++ b/contracts/governance/extensions/GovernorPreventLateQuorum.sol @@ -12,14 +12,12 @@ import "../../utils/math/Math.sol"; * and try to oppose the decision. * * If a vote causes quorum to be reached, the proposal's voting period may be extended so that it does not end before at - * least a given number of blocks have passed (the "vote extension" parameter). This parameter can be set by the - * governance executor (e.g. through a governance proposal). + * least a specified time has passed (the "vote extension" parameter). This parameter can be set through a governance + * proposal. * * _Available since v4.5._ */ abstract contract GovernorPreventLateQuorum is Governor { - using SafeCast for uint256; - uint64 private _voteExtension; /// @custom:oz-retyped-from mapping(uint256 => Timers.BlockNumber) @@ -32,9 +30,9 @@ abstract contract GovernorPreventLateQuorum is Governor { event LateQuorumVoteExtensionSet(uint64 oldVoteExtension, uint64 newVoteExtension); /** - * @dev Initializes the vote extension parameter: the number of blocks that are required to pass since a proposal - * reaches quorum until its voting period ends. If necessary the voting period will be extended beyond the one set - * at proposal creation. + * @dev Initializes the vote extension parameter: the time in either number of blocks or seconds (depending on the governor + * clock mode) that is required to pass since the moment a proposal reaches quorum until its voting period ends. If + * necessary the voting period will be extended beyond the one set during proposal creation. */ constructor(uint64 initialVoteExtension) { _setLateQuorumVoteExtension(initialVoteExtension); diff --git a/contracts/governance/extensions/GovernorTimelockCompound.sol b/contracts/governance/extensions/GovernorTimelockCompound.sol index 629f8f800..912171cc3 100644 --- a/contracts/governance/extensions/GovernorTimelockCompound.sol +++ b/contracts/governance/extensions/GovernorTimelockCompound.sol @@ -21,8 +21,6 @@ import "../../vendor/compound/ICompoundTimelock.sol"; * _Available since v4.3._ */ abstract contract GovernorTimelockCompound is IGovernorTimelock, Governor { - using SafeCast for uint256; - ICompoundTimelock private _timelock; /// @custom:oz-retyped-from mapping(uint256 => GovernorTimelockCompound.ProposalTimelock) @@ -48,18 +46,18 @@ abstract contract GovernorTimelockCompound is IGovernorTimelock, Governor { } /** - * @dev Overridden version of the {Governor-state} function with added support for the `Queued` and `Expired` status. + * @dev Overridden version of the {Governor-state} function with added support for the `Queued` and `Expired` state. */ function state(uint256 proposalId) public view virtual override(IGovernor, Governor) returns (ProposalState) { - ProposalState status = super.state(proposalId); + ProposalState currentState = super.state(proposalId); - if (status != ProposalState.Succeeded) { - return status; + if (currentState != ProposalState.Succeeded) { + return currentState; } uint256 eta = proposalEta(proposalId); if (eta == 0) { - return status; + return currentState; } else if (block.timestamp >= eta + _timelock.GRACE_PERIOD()) { return ProposalState.Expired; } else { @@ -95,7 +93,7 @@ abstract contract GovernorTimelockCompound is IGovernorTimelock, Governor { require(state(proposalId) == ProposalState.Succeeded, "Governor: proposal not successful"); uint256 eta = block.timestamp + _timelock.delay(); - _proposalTimelocks[proposalId] = eta.toUint64(); + _proposalTimelocks[proposalId] = SafeCast.toUint64(eta); for (uint256 i = 0; i < targets.length; ++i) { require( diff --git a/contracts/governance/extensions/GovernorTimelockControl.sol b/contracts/governance/extensions/GovernorTimelockControl.sol index 6aa2556ab..0cf2ea5f0 100644 --- a/contracts/governance/extensions/GovernorTimelockControl.sol +++ b/contracts/governance/extensions/GovernorTimelockControl.sol @@ -47,19 +47,19 @@ abstract contract GovernorTimelockControl is IGovernorTimelock, Governor { } /** - * @dev Overridden version of the {Governor-state} function with added support for the `Queued` status. + * @dev Overridden version of the {Governor-state} function with added support for the `Queued` state. */ function state(uint256 proposalId) public view virtual override(IGovernor, Governor) returns (ProposalState) { - ProposalState status = super.state(proposalId); + ProposalState currentState = super.state(proposalId); - if (status != ProposalState.Succeeded) { - return status; + if (currentState != ProposalState.Succeeded) { + return currentState; } // core tracks execution, so we just have to check if successful proposal have been queued. bytes32 queueid = _timelockIds[proposalId]; if (queueid == bytes32(0)) { - return status; + return currentState; } else if (_timelock.isOperationDone(queueid)) { return ProposalState.Executed; } else if (_timelock.isOperationPending(queueid)) { diff --git a/contracts/governance/extensions/GovernorVotesQuorumFraction.sol b/contracts/governance/extensions/GovernorVotesQuorumFraction.sol index 19c5b194d..403570260 100644 --- a/contracts/governance/extensions/GovernorVotesQuorumFraction.sol +++ b/contracts/governance/extensions/GovernorVotesQuorumFraction.sol @@ -14,7 +14,6 @@ import "../../utils/math/SafeCast.sol"; * _Available since v4.3._ */ abstract contract GovernorVotesQuorumFraction is GovernorVotes { - using SafeCast for *; using Checkpoints for Checkpoints.Trace224; uint256 private _quorumNumerator; // DEPRECATED in favor of _quorumNumeratorHistory @@ -59,7 +58,7 @@ abstract contract GovernorVotesQuorumFraction is GovernorVotes { } // Otherwise, do the binary search - return _quorumNumeratorHistory.upperLookupRecent(timepoint.toUint32()); + return _quorumNumeratorHistory.upperLookupRecent(SafeCast.toUint32(timepoint)); } /** @@ -110,12 +109,12 @@ abstract contract GovernorVotesQuorumFraction is GovernorVotes { // Make sure we keep track of the original numerator in contracts upgraded from a version without checkpoints. if (oldQuorumNumerator != 0 && _quorumNumeratorHistory._checkpoints.length == 0) { _quorumNumeratorHistory._checkpoints.push( - Checkpoints.Checkpoint224({_key: 0, _value: oldQuorumNumerator.toUint224()}) + Checkpoints.Checkpoint224({_key: 0, _value: SafeCast.toUint224(oldQuorumNumerator)}) ); } // Set new quorum for future proposals - _quorumNumeratorHistory.push(clock().toUint32(), newQuorumNumerator.toUint224()); + _quorumNumeratorHistory.push(SafeCast.toUint32(clock()), SafeCast.toUint224(newQuorumNumerator)); emit QuorumNumeratorUpdated(oldQuorumNumerator, newQuorumNumerator); } diff --git a/contracts/governance/utils/IVotes.sol b/contracts/governance/utils/IVotes.sol index c73d0732b..4f2b7eb85 100644 --- a/contracts/governance/utils/IVotes.sol +++ b/contracts/governance/utils/IVotes.sol @@ -25,13 +25,13 @@ interface IVotes { /** * @dev Returns the amount of votes that `account` had at a specific moment in the past. If the `clock()` is - * configured to use block numbers, this will return the value the end of the corresponding block. + * configured to use block numbers, this will return the value at the end of the corresponding block. */ function getPastVotes(address account, uint256 timepoint) external view returns (uint256); /** * @dev Returns the total supply of votes available at a specific moment in the past. If the `clock()` is - * configured to use block numbers, this will return the value the end of the corresponding block. + * configured to use block numbers, this will return the value at the end of the corresponding block. * * NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes. * Votes that have not been delegated are still part of total supply, even though they would not participate in a diff --git a/contracts/governance/utils/Votes.sol b/contracts/governance/utils/Votes.sol index f70cf3831..b24ce824a 100644 --- a/contracts/governance/utils/Votes.sol +++ b/contracts/governance/utils/Votes.sol @@ -59,7 +59,7 @@ abstract contract Votes is Context, EIP712, IERC5805 { // solhint-disable-next-line func-name-mixedcase function CLOCK_MODE() public view virtual override returns (string memory) { // Check that the clock was not modified - require(clock() == block.number); + require(clock() == block.number, "Votes: broken clock mode"); return "mode=blocknumber&from=default"; } @@ -72,7 +72,7 @@ abstract contract Votes is Context, EIP712, IERC5805 { /** * @dev Returns the amount of votes that `account` had at a specific moment in the past. If the `clock()` is - * configured to use block numbers, this will return the value the end of the corresponding block. + * configured to use block numbers, this will return the value at the end of the corresponding block. * * Requirements: * @@ -85,7 +85,7 @@ abstract contract Votes is Context, EIP712, IERC5805 { /** * @dev Returns the total supply of votes available at a specific moment in the past. If the `clock()` is - * configured to use block numbers, this will return the value the end of the corresponding block. + * configured to use block numbers, this will return the value at the end of the corresponding block. * * NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes. * Votes that have not been delegated are still part of total supply, even though they would not participate in a diff --git a/contracts/token/ERC20/extensions/ERC20Votes.sol b/contracts/token/ERC20/extensions/ERC20Votes.sol index f78938e6d..d72d34f81 100644 --- a/contracts/token/ERC20/extensions/ERC20Votes.sol +++ b/contracts/token/ERC20/extensions/ERC20Votes.sol @@ -50,7 +50,7 @@ abstract contract ERC20Votes is ERC20Permit, IERC5805 { // solhint-disable-next-line func-name-mixedcase function CLOCK_MODE() public view virtual override returns (string memory) { // Check that the clock was not modified - require(clock() == block.number); + require(clock() == block.number, "ERC20Votes: broken clock mode"); return "mode=blocknumber&from=default"; } diff --git a/contracts/token/ERC721/extensions/ERC721Votes.sol b/contracts/token/ERC721/extensions/ERC721Votes.sol index 8e6500ec3..31397f107 100644 --- a/contracts/token/ERC721/extensions/ERC721Votes.sol +++ b/contracts/token/ERC721/extensions/ERC721Votes.sol @@ -34,6 +34,8 @@ abstract contract ERC721Votes is ERC721, Votes { /** * @dev Returns the balance of `account`. + * + * WARNING: Overriding this function will likely result in incorrect vote tracking. */ function _getVotingUnits(address account) internal view virtual override returns (uint256) { return balanceOf(account); diff --git a/test/governance/Governor.test.js b/test/governance/Governor.test.js index 1eabaccf0..f867958b5 100644 --- a/test/governance/Governor.test.js +++ b/test/governance/Governor.test.js @@ -70,7 +70,7 @@ contract('Governor', function (accounts) { ); }); - shouldSupportInterfaces(['ERC165', 'ERC1155Receiver', 'Governor', 'GovernorWithParams']); + shouldSupportInterfaces(['ERC165', 'ERC1155Receiver', 'Governor', 'GovernorWithParams', 'GovernorCancel']); shouldBehaveLikeEIP6372(mode); it('deployment check', async function () { @@ -84,7 +84,7 @@ contract('Governor', function (accounts) { it('nominal workflow', async function () { // Before - expect(await this.mock.$_proposalProposer(this.proposal.id)).to.be.equal(constants.ZERO_ADDRESS); + expect(await this.mock.proposalProposer(this.proposal.id)).to.be.equal(constants.ZERO_ADDRESS); expect(await this.mock.hasVoted(this.proposal.id, owner)).to.be.equal(false); expect(await this.mock.hasVoted(this.proposal.id, voter1)).to.be.equal(false); expect(await this.mock.hasVoted(this.proposal.id, voter2)).to.be.equal(false); @@ -149,7 +149,7 @@ contract('Governor', function (accounts) { await expectEvent.inTransaction(txExecute.tx, this.receiver, 'MockFunctionCalled'); // After - expect(await this.mock.$_proposalProposer(this.proposal.id)).to.be.equal(proposer); + expect(await this.mock.proposalProposer(this.proposal.id)).to.be.equal(proposer); expect(await this.mock.hasVoted(this.proposal.id, owner)).to.be.equal(false); expect(await this.mock.hasVoted(this.proposal.id, voter1)).to.be.equal(true); expect(await this.mock.hasVoted(this.proposal.id, voter2)).to.be.equal(true); diff --git a/test/utils/introspection/SupportsInterface.behavior.js b/test/utils/introspection/SupportsInterface.behavior.js index 541f6c611..201a55f47 100644 --- a/test/utils/introspection/SupportsInterface.behavior.js +++ b/test/utils/introspection/SupportsInterface.behavior.js @@ -90,6 +90,7 @@ const INTERFACES = { 'castVoteBySig(uint256,uint8,uint8,bytes32,bytes32)', 'castVoteWithReasonAndParamsBySig(uint256,uint8,string,bytes,uint8,bytes32,bytes32)', ], + GovernorCancel: ['proposalProposer(uint256)', 'cancel(address[],uint256[],bytes[],bytes32)'], GovernorTimelock: ['timelock()', 'proposalEta(uint256)', 'queue(address[],uint256[],bytes[],bytes32)'], ERC2981: ['royaltyInfo(uint256,uint256)'], }; @@ -120,7 +121,7 @@ function shouldSupportInterfaces(interfaces = []) { it('all interfaces are reported as supported', async function () { for (const k of interfaces) { const interfaceId = INTERFACE_IDS[k] ?? k; - expect(await this.contractUnderTest.supportsInterface(interfaceId)).to.equal(true); + expect(await this.contractUnderTest.supportsInterface(interfaceId)).to.equal(true, `does not support ${k}`); } }); @@ -130,7 +131,10 @@ function shouldSupportInterfaces(interfaces = []) { if (INTERFACES[k] === undefined) continue; for (const fnName of INTERFACES[k]) { const fnSig = FN_SIGNATURES[fnName]; - expect(this.contractUnderTest.abi.filter(fn => fn.signature === fnSig).length).to.equal(1); + expect(this.contractUnderTest.abi.filter(fn => fn.signature === fnSig).length).to.equal( + 1, + `did not find ${fnName}`, + ); } } }); From 6aac66d065dc39795fbad1f680f80e3a3d70f2d1 Mon Sep 17 00:00:00 2001 From: Francisco Date: Mon, 24 Apr 2023 13:18:27 +0100 Subject: [PATCH 102/133] Merge release-v4.8 (#4188) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Hadrien Croubois Co-authored-by: Benjamin Co-authored-by: Owen Co-authored-by: Hadrien Croubois Co-authored-by: JulissaDantes Co-authored-by: Ernesto García Co-authored-by: Yamen Merhi Co-authored-by: Pascal Marco Caversaccio Co-authored-by: alpharush <0xalpharush@protonmail.com> Co-authored-by: Paul Razvan Berg --- .changeset/silent-pugs-scream.md | 5 ----- .changeset/thirty-shrimps-mix.md | 5 ----- CHANGELOG.md | 5 +++++ .../governance/compatibility/GovernorCompatibilityBravo.sol | 2 +- contracts/proxy/ERC1967/ERC1967Upgrade.sol | 2 +- contracts/proxy/transparent/ProxyAdmin.sol | 2 +- contracts/proxy/transparent/TransparentUpgradeableProxy.sol | 2 +- 7 files changed, 9 insertions(+), 14 deletions(-) delete mode 100644 .changeset/silent-pugs-scream.md delete mode 100644 .changeset/thirty-shrimps-mix.md diff --git a/.changeset/silent-pugs-scream.md b/.changeset/silent-pugs-scream.md deleted file mode 100644 index c92d12486..000000000 --- a/.changeset/silent-pugs-scream.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'openzeppelin-solidity': patch ---- - -`GovernorCompatibilityBravo`: Fix encoding of proposal data when signatures are missing. diff --git a/.changeset/thirty-shrimps-mix.md b/.changeset/thirty-shrimps-mix.md deleted file mode 100644 index 656edbf92..000000000 --- a/.changeset/thirty-shrimps-mix.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'openzeppelin-solidity': patch ---- - -`TransparentUpgradeableProxy`: Fix transparency in case of selector clash with non-decodable calldata or payable mutability. diff --git a/CHANGELOG.md b/CHANGELOG.md index 333b6d4a3..ffbd3acea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,11 @@ - `ERC777`: The `ERC777` token standard is no longer supported by OpenZeppelin. Our implementation is now deprecated and will be removed in the next major release. The corresponding standard interfaces remain available. ([#4066](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4066)) - `ERC1820Implementer`: The `ERC1820` pseudo-introspection mechanism is no longer supported by OpenZeppelin. Our implementation is now deprecated and will be removed in the next major release. The corresponding standard interfaces remain available. ([#4066](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4066)) +## 4.8.3 (2023-04-13) + +- `GovernorCompatibilityBravo`: Fix encoding of proposal data when signatures are missing. +- `TransparentUpgradeableProxy`: Fix transparency in case of selector clash with non-decodable calldata or payable mutability. ([#4154](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4154)) + ## 4.8.2 (2023-03-02) - `ERC721Consecutive`: Fixed a bug when `_mintConsecutive` is used for batches of size 1 that could lead to balance overflow. Refer to the breaking changes section in the changelog for a note on the behavior of `ERC721._beforeTokenTransfer`. diff --git a/contracts/governance/compatibility/GovernorCompatibilityBravo.sol b/contracts/governance/compatibility/GovernorCompatibilityBravo.sol index 0fbb4e17c..1332ac79d 100644 --- a/contracts/governance/compatibility/GovernorCompatibilityBravo.sol +++ b/contracts/governance/compatibility/GovernorCompatibilityBravo.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v4.8.0) (governance/compatibility/GovernorCompatibilityBravo.sol) +// OpenZeppelin Contracts (last updated v4.8.3) (governance/compatibility/GovernorCompatibilityBravo.sol) pragma solidity ^0.8.0; diff --git a/contracts/proxy/ERC1967/ERC1967Upgrade.sol b/contracts/proxy/ERC1967/ERC1967Upgrade.sol index a79c10502..3942ca699 100644 --- a/contracts/proxy/ERC1967/ERC1967Upgrade.sol +++ b/contracts/proxy/ERC1967/ERC1967Upgrade.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol) +// OpenZeppelin Contracts (last updated v4.8.3) (proxy/ERC1967/ERC1967Upgrade.sol) pragma solidity ^0.8.2; diff --git a/contracts/proxy/transparent/ProxyAdmin.sol b/contracts/proxy/transparent/ProxyAdmin.sol index 1a9698196..571530595 100644 --- a/contracts/proxy/transparent/ProxyAdmin.sol +++ b/contracts/proxy/transparent/ProxyAdmin.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts v4.4.1 (proxy/transparent/ProxyAdmin.sol) +// OpenZeppelin Contracts (last updated v4.8.3) (proxy/transparent/ProxyAdmin.sol) pragma solidity ^0.8.0; diff --git a/contracts/proxy/transparent/TransparentUpgradeableProxy.sol b/contracts/proxy/transparent/TransparentUpgradeableProxy.sol index d8765fc9e..4e2b0c759 100644 --- a/contracts/proxy/transparent/TransparentUpgradeableProxy.sol +++ b/contracts/proxy/transparent/TransparentUpgradeableProxy.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v4.7.0) (proxy/transparent/TransparentUpgradeableProxy.sol) +// OpenZeppelin Contracts (last updated v4.8.3) (proxy/transparent/TransparentUpgradeableProxy.sol) pragma solidity ^0.8.0; From 1a079d258b15409970f181702669fa8738d0edef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Garc=C3=ADa?= Date: Tue, 25 Apr 2023 13:31:01 +0200 Subject: [PATCH 103/133] Improve Address tests (#4191) --- contracts/mocks/CallReceiverMock.sol | 4 +++ contracts/utils/Address.sol | 2 +- test/utils/Address.test.js | 40 ++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/contracts/mocks/CallReceiverMock.sol b/contracts/mocks/CallReceiverMock.sol index 344a1054b..492adbe92 100644 --- a/contracts/mocks/CallReceiverMock.sol +++ b/contracts/mocks/CallReceiverMock.sol @@ -14,6 +14,10 @@ contract CallReceiverMock { return "0x1234"; } + function mockFunctionEmptyReturn() public payable { + emit MockFunctionCalled(); + } + function mockFunctionWithArgs(uint256 a, uint256 b) public payable returns (string memory) { emit MockFunctionCalledWithArgs(a, b); diff --git a/contracts/utils/Address.sol b/contracts/utils/Address.sol index 433a866d7..5ff14140a 100644 --- a/contracts/utils/Address.sol +++ b/contracts/utils/Address.sol @@ -59,7 +59,7 @@ library Address { * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the - * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); diff --git a/test/utils/Address.test.js b/test/utils/Address.test.js index a78ae14e6..4f9f9eea1 100644 --- a/test/utils/Address.test.js +++ b/test/utils/Address.test.js @@ -107,6 +107,14 @@ contract('Address', function (accounts) { await expectEvent.inTransaction(receipt.tx, CallReceiverMock, 'MockFunctionCalled'); }); + it('calls the requested empty return function', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunctionEmptyReturn().encodeABI(); + + const receipt = await this.mock.$functionCall(this.target.address, abiEncodedCall); + + await expectEvent.inTransaction(receipt.tx, CallReceiverMock, 'MockFunctionCalled'); + }); + it('reverts when the called function reverts with no reason', async function () { const abiEncodedCall = this.target.contract.methods.mockFunctionRevertsNoReason().encodeABI(); @@ -137,6 +145,11 @@ contract('Address', function (accounts) { await expectRevert.unspecified(this.mock.$functionCall(this.target.address, abiEncodedCall)); }); + it('bubbles up error message if specified', async function () { + const errorMsg = 'Address: expected error'; + await expectRevert(this.mock.$functionCall(this.target.address, '0x12345678', errorMsg), errorMsg); + }); + it('reverts when function does not exist', async function () { const abiEncodedCall = web3.eth.abi.encodeFunctionCall( { @@ -237,6 +250,11 @@ contract('Address', function (accounts) { 'Address: low-level call with value failed', ); }); + + it('bubbles up error message if specified', async function () { + const errorMsg = 'Address: expected error'; + await expectRevert(this.mock.$functionCallWithValue(this.target.address, '0x12345678', 0, errorMsg), errorMsg); + }); }); }); @@ -277,6 +295,11 @@ contract('Address', function (accounts) { await expectRevert(this.mock.$functionStaticCall(recipient, abiEncodedCall), 'Address: call to non-contract'); }); + + it('bubbles up error message if specified', async function () { + const errorMsg = 'Address: expected error'; + await expectRevert(this.mock.$functionCallWithValue(this.target.address, '0x12345678', 0, errorMsg), errorMsg); + }); }); describe('functionDelegateCall', function () { @@ -317,5 +340,22 @@ contract('Address', function (accounts) { await expectRevert(this.mock.$functionDelegateCall(recipient, abiEncodedCall), 'Address: call to non-contract'); }); + + it('bubbles up error message if specified', async function () { + const errorMsg = 'Address: expected error'; + await expectRevert(this.mock.$functionCallWithValue(this.target.address, '0x12345678', 0, errorMsg), errorMsg); + }); + }); + + describe('verifyCallResult', function () { + it('returns returndata on success', async function () { + const returndata = '0x123abc'; + expect(await this.mock.$verifyCallResult(true, returndata, '')).to.equal(returndata); + }); + + it('reverts with return data and error m', async function () { + const errorMsg = 'Address: expected error'; + await expectRevert(this.mock.$verifyCallResult(false, '0x', errorMsg), errorMsg); + }); }); }); From 8f14d52b7366eb8dcdbf40a92b2d1cb14ded9a13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Garc=C3=ADa?= Date: Tue, 25 Apr 2023 17:57:16 +0200 Subject: [PATCH 104/133] Fix Checkpoints fuzz overflow (#4184) Co-authored-by: Francisco --- scripts/generate/templates/Checkpoints.t.js | 22 ++++++++++------- test/utils/Checkpoints.t.sol | 26 +++++++++++++-------- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/scripts/generate/templates/Checkpoints.t.js b/scripts/generate/templates/Checkpoints.t.js index 84b5992ad..b3da933a1 100644 --- a/scripts/generate/templates/Checkpoints.t.js +++ b/scripts/generate/templates/Checkpoints.t.js @@ -86,10 +86,12 @@ function testPush( if (keys.length > 0) { ${opts.keyTypeName} lastKey = keys[keys.length - 1]; - pastKey = _bound${capitalize(opts.keyTypeName)}(pastKey, 0, lastKey - 1); - - vm.expectRevert(); - this.push(pastKey, values[keys.length % values.length]); + if (lastKey > 0) { + pastKey = _bound${capitalize(opts.keyTypeName)}(pastKey, 0, lastKey - 1); + + vm.expectRevert(); + this.push(pastKey, values[keys.length % values.length]); + } } } @@ -173,11 +175,13 @@ function testPush( // Can't push any key in the past if (keys.length > 0) { ${opts.keyTypeName} lastKey = keys[keys.length - 1]; - pastKey = _bound${capitalize(opts.keyTypeName)}(pastKey, 0, lastKey - 1); - - vm.roll(pastKey); - vm.expectRevert(); - this.push(values[keys.length % values.length]); + if (lastKey > 0) { + pastKey = _bound${capitalize(opts.keyTypeName)}(pastKey, 0, lastKey - 1); + + vm.roll(pastKey); + vm.expectRevert(); + this.push(values[keys.length % values.length]); + } } } diff --git a/test/utils/Checkpoints.t.sol b/test/utils/Checkpoints.t.sol index abdf8b436..f2cb587d5 100644 --- a/test/utils/Checkpoints.t.sol +++ b/test/utils/Checkpoints.t.sol @@ -66,11 +66,13 @@ contract CheckpointsHistoryTest is Test { // Can't push any key in the past if (keys.length > 0) { uint32 lastKey = keys[keys.length - 1]; - pastKey = _boundUint32(pastKey, 0, lastKey - 1); + if (lastKey > 0) { + pastKey = _boundUint32(pastKey, 0, lastKey - 1); - vm.roll(pastKey); - vm.expectRevert(); - this.push(values[keys.length % values.length]); + vm.roll(pastKey); + vm.expectRevert(); + this.push(values[keys.length % values.length]); + } } } @@ -185,10 +187,12 @@ contract CheckpointsTrace224Test is Test { if (keys.length > 0) { uint32 lastKey = keys[keys.length - 1]; - pastKey = _boundUint32(pastKey, 0, lastKey - 1); + if (lastKey > 0) { + pastKey = _boundUint32(pastKey, 0, lastKey - 1); - vm.expectRevert(); - this.push(pastKey, values[keys.length % values.length]); + vm.expectRevert(); + this.push(pastKey, values[keys.length % values.length]); + } } } @@ -291,10 +295,12 @@ contract CheckpointsTrace160Test is Test { if (keys.length > 0) { uint96 lastKey = keys[keys.length - 1]; - pastKey = _boundUint96(pastKey, 0, lastKey - 1); + if (lastKey > 0) { + pastKey = _boundUint96(pastKey, 0, lastKey - 1); - vm.expectRevert(); - this.push(pastKey, values[keys.length % values.length]); + vm.expectRevert(); + this.push(pastKey, values[keys.length % values.length]); + } } } From f959d7e4e6ee0b022b41e5b644c79369869d8411 Mon Sep 17 00:00:00 2001 From: Pascal Marco Caversaccio Date: Tue, 25 Apr 2023 17:57:50 +0200 Subject: [PATCH 105/133] Fix release note in `IERC1967` (#4183) --- contracts/interfaces/IERC1967.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/interfaces/IERC1967.sol b/contracts/interfaces/IERC1967.sol index e5deebee9..ab4450eec 100644 --- a/contracts/interfaces/IERC1967.sol +++ b/contracts/interfaces/IERC1967.sol @@ -5,7 +5,7 @@ pragma solidity ^0.8.0; /** * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC. * - * _Available since v4.9._ + * _Available since v4.8.3._ */ interface IERC1967 { /** From 44d6053b4376421a5b45ace021934b72d649d09b Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Fri, 28 Apr 2023 14:01:41 +0200 Subject: [PATCH 106/133] Only run FV on new or updated specs (#4195) --- .github/workflows/formal-verification.yml | 14 ++++- certora/run.js | 64 ++++++++++++++++------- certora/specs/Ownable.spec | 4 +- 3 files changed, 61 insertions(+), 21 deletions(-) diff --git a/.github/workflows/formal-verification.yml b/.github/workflows/formal-verification.yml index 29c02541c..f94152a52 100644 --- a/.github/workflows/formal-verification.yml +++ b/.github/workflows/formal-verification.yml @@ -33,8 +33,20 @@ jobs: if: github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'formal-verification') steps: - uses: actions/checkout@v3 + with: + fetch-depth: 0 - name: Set up environment uses: ./.github/actions/setup + - name: identify specs that need to be run + id: arguments + run: | + if [[ ${{ github.event_name }} = 'pull_request' ]]; + then + RESULT=$(git diff ${{ github.event.pull_request.head.sha }}..${{ github.event.pull_request.base.sha }} --name-only certora/specs/*.spec | while IFS= read -r file; do [[ -f $file ]] && basename "${file%.spec}"; done | tr "\n" " ") + else + RESULT='--all' + fi + echo "result=$RESULT" >> "$GITHUB_OUTPUT" - name: Install python uses: actions/setup-python@v4 with: @@ -55,6 +67,6 @@ jobs: - name: Verify specification run: | make -C certora apply - node certora/run.js >> "$GITHUB_STEP_SUMMARY" + node certora/run.js ${{ steps.arguments.outputs.result }} >> "$GITHUB_STEP_SUMMARY" env: CERTORAKEY: ${{ secrets.CERTORAKEY }} diff --git a/certora/run.js b/certora/run.js index f3234c1a3..2dc7d0181 100644 --- a/certora/run.js +++ b/certora/run.js @@ -1,37 +1,65 @@ #!/usr/bin/env node // USAGE: -// node certora/run.js [[CONTRACT_NAME:]SPEC_NAME] [OPTIONS...] +// node certora/run.js [[CONTRACT_NAME:]SPEC_NAME]* [--all] [--options OPTIONS...] [--specs PATH] // EXAMPLES: +// node certora/run.js --all // node certora/run.js AccessControl // node certora/run.js AccessControlHarness:AccessControl -const MAX_PARALLEL = 4; - -let specs = require(__dirname + '/specs.json'); - const proc = require('child_process'); const { PassThrough } = require('stream'); const events = require('events'); -const limit = require('p-limit')(MAX_PARALLEL); -let [, , request = '', ...extraOptions] = process.argv; -if (request.startsWith('-')) { - extraOptions.unshift(request); - request = ''; +const argv = require('yargs') + .env('') + .options({ + all: { + alias: 'a', + type: 'boolean', + }, + spec: { + alias: 's', + type: 'string', + default: __dirname + '/specs.json', + }, + parallel: { + alias: 'p', + type: 'number', + default: 4, + }, + options: { + alias: 'o', + type: 'array', + default: [], + }, + }).argv; + +function match(entry, request) { + const [reqSpec, reqContract] = request.split(':').reverse(); + return entry.spec == reqSpec && (!reqContract || entry.contract == reqContract); } -if (request) { - const [reqSpec, reqContract] = request.split(':').reverse(); - specs = Object.values(specs).filter(s => reqSpec === s.spec && (!reqContract || reqContract === s.contract)); - if (specs.length === 0) { - console.error(`Error: Requested spec '${request}' not found in specs.json`); - process.exit(1); +const specs = require(argv.spec).filter(s => argv.all || argv._.some(r => match(s, r))); +const limit = require('p-limit')(argv.parallel); + +if (argv._.length == 0 && !argv.all) { + console.error(`Warning: No specs requested. Did you forgot to toggle '--all'?`); +} + +for (const r of argv._) { + if (!specs.some(s => match(s, r))) { + console.error(`Error: Requested spec '${r}' not found in ${argv.spec}`); + process.exitCode = 1; } } -for (const { spec, contract, files, options = [] } of Object.values(specs)) { - limit(runCertora, spec, contract, files, [...options.flatMap(opt => opt.split(' ')), ...extraOptions]); +if (process.exitCode) { + process.exit(process.exitCode); +} + +for (const { spec, contract, files, options = [] } of specs) { + limit(runCertora, spec, contract, files, [...options.flatMap(opt => opt.split(' ')), ...argv.options]); } // Run certora, aggregate the output and print it at the end diff --git a/certora/specs/Ownable.spec b/certora/specs/Ownable.spec index 48bd84d13..4fdfeb09c 100644 --- a/certora/specs/Ownable.spec +++ b/certora/specs/Ownable.spec @@ -62,10 +62,10 @@ rule onlyCurrentOwnerCanCallOnlyOwner(env e) { │ Rule: ownership can only change in specific ways │ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ */ -rule onlyOwnerOrPendingOwnerCanChangeOwnership(env e, method f) { +rule onlyOwnerOrPendingOwnerCanChangeOwnership(env e) { address oldCurrent = owner(); - calldataarg args; + method f; calldataarg args; f(e, args); address newCurrent = owner(); From d23f818a59b47e496a431e3e7c8b89dffe4f74d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Garc=C3=ADa?= Date: Fri, 28 Apr 2023 15:09:58 +0200 Subject: [PATCH 107/133] Fix AccessControlDefaultAdminRules admin consistency (#4177) Co-authored-by: Francisco Co-authored-by: Hadrien Croubois --- .../access/AccessControlDefaultAdminRules.sol | 2 +- test/access/AccessControl.behavior.js | 30 +++++++++++-------- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/contracts/access/AccessControlDefaultAdminRules.sol b/contracts/access/AccessControlDefaultAdminRules.sol index 43fca9350..0c640fb99 100644 --- a/contracts/access/AccessControlDefaultAdminRules.sol +++ b/contracts/access/AccessControlDefaultAdminRules.sol @@ -136,7 +136,7 @@ abstract contract AccessControlDefaultAdminRules is IAccessControlDefaultAdminRu * @dev See {AccessControl-_revokeRole}. */ function _revokeRole(bytes32 role, address account) internal virtual override { - if (role == DEFAULT_ADMIN_ROLE) { + if (role == DEFAULT_ADMIN_ROLE && account == _currentDefaultAdmin) { delete _currentDefaultAdmin; } super._revokeRole(role, account); diff --git a/test/access/AccessControl.behavior.js b/test/access/AccessControl.behavior.js index 6c88aa274..49ab44b58 100644 --- a/test/access/AccessControl.behavior.js +++ b/test/access/AccessControl.behavior.js @@ -513,15 +513,12 @@ function shouldBehaveLikeAccessControlDefaultAdminRules(errorPrefix, delay, defa }); describe('when caller is pending default admin and delay has passed', function () { - let from; - beforeEach(async function () { await time.setNextBlockTimestamp(acceptSchedule.addn(1)); - from = newDefaultAdmin; }); it('accepts a transfer and changes default admin', async function () { - const receipt = await this.accessControl.acceptDefaultAdminTransfer({ from }); + const receipt = await this.accessControl.acceptDefaultAdminTransfer({ from: newDefaultAdmin }); // Storage changes expect(await this.accessControl.hasRole(DEFAULT_ADMIN_ROLE, defaultAdmin)).to.be.false; @@ -625,10 +622,9 @@ function shouldBehaveLikeAccessControlDefaultAdminRules(errorPrefix, delay, defa describe('renounces admin', function () { let delayPassed; - let from = defaultAdmin; beforeEach(async function () { - await this.accessControl.beginDefaultAdminTransfer(constants.ZERO_ADDRESS, { from }); + await this.accessControl.beginDefaultAdminTransfer(constants.ZERO_ADDRESS, { from: defaultAdmin }); delayPassed = web3.utils .toBN(await time.latest()) .add(delay) @@ -638,27 +634,37 @@ function shouldBehaveLikeAccessControlDefaultAdminRules(errorPrefix, delay, defa it('reverts if caller is not default admin', async function () { await time.setNextBlockTimestamp(delayPassed); await expectRevert( - this.accessControl.renounceRole(DEFAULT_ADMIN_ROLE, other, { from }), + this.accessControl.renounceRole(DEFAULT_ADMIN_ROLE, other, { from: defaultAdmin }), `${errorPrefix}: can only renounce roles for self`, ); }); + it('keeps defaultAdmin consistent with hasRole if another non-defaultAdmin user renounces the DEFAULT_ADMIN_ROLE', async function () { + await time.setNextBlockTimestamp(delayPassed); + + // This passes because it's a noop + await this.accessControl.renounceRole(DEFAULT_ADMIN_ROLE, other, { from: other }); + + expect(await this.accessControl.hasRole(DEFAULT_ADMIN_ROLE, defaultAdmin)).to.be.true; + expect(await this.accessControl.defaultAdmin()).to.be.equal(defaultAdmin); + }); + it('renounces role', async function () { await time.setNextBlockTimestamp(delayPassed); - const receipt = await this.accessControl.renounceRole(DEFAULT_ADMIN_ROLE, from, { from }); + const receipt = await this.accessControl.renounceRole(DEFAULT_ADMIN_ROLE, defaultAdmin, { from: defaultAdmin }); expect(await this.accessControl.hasRole(DEFAULT_ADMIN_ROLE, defaultAdmin)).to.be.false; - expect(await this.accessControl.hasRole(constants.ZERO_ADDRESS, defaultAdmin)).to.be.false; + expect(await this.accessControl.defaultAdmin()).to.be.equal(constants.ZERO_ADDRESS); expectEvent(receipt, 'RoleRevoked', { role: DEFAULT_ADMIN_ROLE, - account: from, + account: defaultAdmin, }); expect(await this.accessControl.owner()).to.equal(constants.ZERO_ADDRESS); }); it('allows to recover access using the internal _grantRole', async function () { await time.setNextBlockTimestamp(delayPassed); - await this.accessControl.renounceRole(DEFAULT_ADMIN_ROLE, from, { from }); + await this.accessControl.renounceRole(DEFAULT_ADMIN_ROLE, defaultAdmin, { from: defaultAdmin }); const grantRoleReceipt = await this.accessControl.$_grantRole(DEFAULT_ADMIN_ROLE, other); expectEvent(grantRoleReceipt, 'RoleGranted', { @@ -681,7 +687,7 @@ function shouldBehaveLikeAccessControlDefaultAdminRules(errorPrefix, delay, defa it(`reverts if block.timestamp is ${tag} to schedule`, async function () { await time.setNextBlockTimestamp(delayNotPassed.toNumber() + fromSchedule); await expectRevert( - this.accessControl.renounceRole(DEFAULT_ADMIN_ROLE, defaultAdmin, { from }), + this.accessControl.renounceRole(DEFAULT_ADMIN_ROLE, defaultAdmin, { from: defaultAdmin }), `${errorPrefix}: only can renounce in two delayed steps`, ); }); From 6ff415de6be00f52900c8573cc761b807acfd88b Mon Sep 17 00:00:00 2001 From: Francisco Date: Fri, 28 Apr 2023 21:15:15 +0100 Subject: [PATCH 108/133] Downgrade Node for Slither (#4202) --- .github/workflows/checks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index c6b42dd82..2d5c15159 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -86,7 +86,7 @@ jobs: - run: rm foundry.toml - uses: crytic/slither-action@v0.3.0 with: - node-version: 18 + node-version: 18.15 codespell: if: github.repository != 'OpenZeppelin/openzeppelin-contracts-upgradeable' From ab2604ac5b791adf3c5e2397e65128cb56954edd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Garc=C3=ADa?= Date: Tue, 2 May 2023 11:36:56 +0200 Subject: [PATCH 109/133] Add reentrancy test cases for TimelockController (#4200) Co-authored-by: Francisco --- contracts/mocks/TimelockReentrant.sol | 26 ++++ test/governance/TimelockController.test.js | 155 +++++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 contracts/mocks/TimelockReentrant.sol diff --git a/contracts/mocks/TimelockReentrant.sol b/contracts/mocks/TimelockReentrant.sol new file mode 100644 index 000000000..a9344f50d --- /dev/null +++ b/contracts/mocks/TimelockReentrant.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "../utils/Address.sol"; + +contract TimelockReentrant { + address private _reenterTarget; + bytes private _reenterData; + bool _reentered; + + function disableReentrancy() external { + _reentered = true; + } + + function enableRentrancy(address target, bytes calldata data) external { + _reenterTarget = target; + _reenterData = data; + } + + function reenter() external { + if (!_reentered) { + _reentered = true; + Address.functionCall(_reenterTarget, _reenterData); + } + } +} diff --git a/test/governance/TimelockController.test.js b/test/governance/TimelockController.test.js index dde923564..82a84746e 100644 --- a/test/governance/TimelockController.test.js +++ b/test/governance/TimelockController.test.js @@ -10,6 +10,7 @@ const CallReceiverMock = artifacts.require('CallReceiverMock'); const Implementation2 = artifacts.require('Implementation2'); const ERC721 = artifacts.require('$ERC721'); const ERC1155 = artifacts.require('$ERC1155'); +const TimelockReentrant = artifacts.require('$TimelockReentrant'); const MINDELAY = time.duration.days(1); @@ -345,6 +346,82 @@ contract('TimelockController', function (accounts) { `AccessControl: account ${other.toLowerCase()} is missing role ${EXECUTOR_ROLE}`, ); }); + + it('prevents reentrancy execution', async function () { + // Create operation + const reentrant = await TimelockReentrant.new(); + const reentrantOperation = genOperation( + reentrant.address, + 0, + reentrant.contract.methods.reenter().encodeABI(), + ZERO_BYTES32, + salt, + ); + + // Schedule so it can be executed + await this.mock.schedule( + reentrantOperation.target, + reentrantOperation.value, + reentrantOperation.data, + reentrantOperation.predecessor, + reentrantOperation.salt, + MINDELAY, + { from: proposer }, + ); + + // Advance on time to make the operation executable + const timestamp = await this.mock.getTimestamp(reentrantOperation.id); + await time.increaseTo(timestamp); + + // Grant executor role to the reentrant contract + await this.mock.grantRole(EXECUTOR_ROLE, reentrant.address, { from: admin }); + + // Prepare reenter + const data = this.mock.contract.methods + .execute( + reentrantOperation.target, + reentrantOperation.value, + reentrantOperation.data, + reentrantOperation.predecessor, + reentrantOperation.salt, + ) + .encodeABI(); + await reentrant.enableRentrancy(this.mock.address, data); + + // Expect to fail + await expectRevert( + this.mock.execute( + reentrantOperation.target, + reentrantOperation.value, + reentrantOperation.data, + reentrantOperation.predecessor, + reentrantOperation.salt, + { from: executor }, + ), + 'TimelockController: operation is not ready', + ); + + // Disable reentrancy + await reentrant.disableReentrancy(); + const nonReentrantOperation = reentrantOperation; // Not anymore + + // Try again successfully + const receipt = await this.mock.execute( + nonReentrantOperation.target, + nonReentrantOperation.value, + nonReentrantOperation.data, + nonReentrantOperation.predecessor, + nonReentrantOperation.salt, + { from: executor }, + ); + expectEvent(receipt, 'CallExecuted', { + id: nonReentrantOperation.id, + index: web3.utils.toBN(0), + target: nonReentrantOperation.target, + value: web3.utils.toBN(nonReentrantOperation.value), + data: nonReentrantOperation.data, + }); + }); }); }); }); @@ -632,6 +709,84 @@ contract('TimelockController', function (accounts) { 'TimelockController: length mismatch', ); }); + + it('prevents reentrancy execution', async function () { + // Create operation + const reentrant = await TimelockReentrant.new(); + const reentrantBatchOperation = genOperationBatch( + [reentrant.address], + [0], + [reentrant.contract.methods.reenter().encodeABI()], + ZERO_BYTES32, + salt, + ); + + // Schedule so it can be executed + await this.mock.scheduleBatch( + reentrantBatchOperation.targets, + reentrantBatchOperation.values, + reentrantBatchOperation.payloads, + reentrantBatchOperation.predecessor, + reentrantBatchOperation.salt, + MINDELAY, + { from: proposer }, + ); + + // Advance on time to make the operation executable + const timestamp = await this.mock.getTimestamp(reentrantBatchOperation.id); + await time.increaseTo(timestamp); + + // Grant executor role to the reentrant contract + await this.mock.grantRole(EXECUTOR_ROLE, reentrant.address, { from: admin }); + + // Prepare reenter + const data = this.mock.contract.methods + .executeBatch( + reentrantBatchOperation.targets, + reentrantBatchOperation.values, + reentrantBatchOperation.payloads, + reentrantBatchOperation.predecessor, + reentrantBatchOperation.salt, + ) + .encodeABI(); + await reentrant.enableRentrancy(this.mock.address, data); + + // Expect to fail + await expectRevert( + this.mock.executeBatch( + reentrantBatchOperation.targets, + reentrantBatchOperation.values, + reentrantBatchOperation.payloads, + reentrantBatchOperation.predecessor, + reentrantBatchOperation.salt, + { from: executor }, + ), + 'TimelockController: operation is not ready', + ); + + // Disable reentrancy + await reentrant.disableReentrancy(); + const nonReentrantBatchOperation = reentrantBatchOperation; // Not anymore + + // Try again successfully + const receipt = await this.mock.executeBatch( + nonReentrantBatchOperation.targets, + nonReentrantBatchOperation.values, + nonReentrantBatchOperation.payloads, + nonReentrantBatchOperation.predecessor, + nonReentrantBatchOperation.salt, + { from: executor }, + ); + for (const i in nonReentrantBatchOperation.targets) { + expectEvent(receipt, 'CallExecuted', { + id: nonReentrantBatchOperation.id, + index: web3.utils.toBN(i), + target: nonReentrantBatchOperation.targets[i], + value: web3.utils.toBN(nonReentrantBatchOperation.values[i]), + data: nonReentrantBatchOperation.payloads[i], + }); + } + }); }); }); From 0a2a33be301720ae6a0aabcd739e74606bc35ef6 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Wed, 3 May 2023 04:54:23 +0200 Subject: [PATCH 110/133] Add formal verification specs for EnumerableSet & EnumerableMap (#4167) Co-authored-by: Francisco --- certora/harnesses/EnumerableMapHarness.sol | 55 ++++ certora/harnesses/EnumerableSetHarness.sol | 35 +++ certora/run.js | 0 certora/specs.json | 10 + certora/specs/EnumerableMap.spec | 334 +++++++++++++++++++++ certora/specs/EnumerableSet.spec | 247 +++++++++++++++ 6 files changed, 681 insertions(+) create mode 100644 certora/harnesses/EnumerableMapHarness.sol create mode 100644 certora/harnesses/EnumerableSetHarness.sol mode change 100644 => 100755 certora/run.js create mode 100644 certora/specs/EnumerableMap.spec create mode 100644 certora/specs/EnumerableSet.spec diff --git a/certora/harnesses/EnumerableMapHarness.sol b/certora/harnesses/EnumerableMapHarness.sol new file mode 100644 index 000000000..3bcf1b50a --- /dev/null +++ b/certora/harnesses/EnumerableMapHarness.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../patched/utils/structs/EnumerableMap.sol"; + +contract EnumerableMapHarness { + using EnumerableMap for EnumerableMap.Bytes32ToBytes32Map; + + EnumerableMap.Bytes32ToBytes32Map private _map; + + function set(bytes32 key, bytes32 value) public returns (bool) { + return _map.set(key, value); + } + + function remove(bytes32 key) public returns (bool) { + return _map.remove(key); + } + + function contains(bytes32 key) public view returns (bool) { + return _map.contains(key); + } + + function length() public view returns (uint256) { + return _map.length(); + } + + function key_at(uint256 index) public view returns (bytes32) { + (bytes32 key,) = _map.at(index); + return key; + } + + function value_at(uint256 index) public view returns (bytes32) { + (,bytes32 value) = _map.at(index); + return value; + } + + function tryGet_contains(bytes32 key) public view returns (bool) { + (bool contained,) = _map.tryGet(key); + return contained; + } + + function tryGet_value(bytes32 key) public view returns (bytes32) { + (,bytes32 value) = _map.tryGet(key); + return value; + } + + function get(bytes32 key) public view returns (bytes32) { + return _map.get(key); + } + + function _indexOf(bytes32 key) public view returns (uint256) { + return _map._keys._inner._indexes[key]; + } +} diff --git a/certora/harnesses/EnumerableSetHarness.sol b/certora/harnesses/EnumerableSetHarness.sol new file mode 100644 index 000000000..64383e6a4 --- /dev/null +++ b/certora/harnesses/EnumerableSetHarness.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../patched/utils/structs/EnumerableSet.sol"; + +contract EnumerableSetHarness { + using EnumerableSet for EnumerableSet.Bytes32Set; + + EnumerableSet.Bytes32Set private _set; + + function add(bytes32 value) public returns (bool) { + return _set.add(value); + } + + function remove(bytes32 value) public returns (bool) { + return _set.remove(value); + } + + function contains(bytes32 value) public view returns (bool) { + return _set.contains(value); + } + + function length() public view returns (uint256) { + return _set.length(); + } + + function at_(uint256 index) public view returns (bytes32) { + return _set.at(index); + } + + function _indexOf(bytes32 value) public view returns (uint256) { + return _set._inner._indexes[value]; + } +} diff --git a/certora/run.js b/certora/run.js old mode 100644 new mode 100755 diff --git a/certora/specs.json b/certora/specs.json index 39ba8c235..6f8f57bdf 100644 --- a/certora/specs.json +++ b/certora/specs.json @@ -62,6 +62,16 @@ "contract": "InitializableHarness", "files": ["certora/harnesses/InitializableHarness.sol"] }, + { + "spec": "EnumerableSet", + "contract": "EnumerableSetHarness", + "files": ["certora/harnesses/EnumerableSetHarness.sol"] + }, + { + "spec": "EnumerableMap", + "contract": "EnumerableMapHarness", + "files": ["certora/harnesses/EnumerableMapHarness.sol"] + }, { "spec": "TimelockController", "contract": "TimelockControllerHarness", diff --git a/certora/specs/EnumerableMap.spec b/certora/specs/EnumerableMap.spec new file mode 100644 index 000000000..56ef854c6 --- /dev/null +++ b/certora/specs/EnumerableMap.spec @@ -0,0 +1,334 @@ +import "helpers.spec" + +methods { + // library + set(bytes32,bytes32) returns (bool) envfree + remove(bytes32) returns (bool) envfree + contains(bytes32) returns (bool) envfree + length() returns (uint256) envfree + key_at(uint256) returns (bytes32) envfree + value_at(uint256) returns (bytes32) envfree + tryGet_contains(bytes32) returns (bool) envfree + tryGet_value(bytes32) returns (bytes32) envfree + get(bytes32) returns (bytes32) envfree + + // FV + _indexOf(bytes32) returns (uint256) envfree +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Helpers │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +function sanity() returns bool { + return length() < max_uint256; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: the value mapping is empty for keys that are not in the EnumerableMap. │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant noValueIfNotContained(bytes32 key) + !contains(key) => tryGet_value(key) == 0 + { + preserved set(bytes32 otherKey, bytes32 someValue) { + require sanity(); + } + } + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: All indexed keys are contained │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant indexedContained(uint256 index) + index < length() => contains(key_at(index)) + { + preserved { + requireInvariant consistencyIndex(index); + requireInvariant consistencyIndex(to_uint256(length() - 1)); + } + } + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: A value can only be stored at a single location │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant atUniqueness(uint256 index1, uint256 index2) + index1 == index2 <=> key_at(index1) == key_at(index2) + { + preserved remove(bytes32 key) { + requireInvariant atUniqueness(index1, to_uint256(length() - 1)); + requireInvariant atUniqueness(index2, to_uint256(length() - 1)); + } + } + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: index <> value relationship is consistent │ +│ │ +│ Note that the two consistencyXxx invariants, put together, prove that at_ and _indexOf 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). │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant consistencyIndex(uint256 index) + index < length() => _indexOf(key_at(index)) == index + 1 + { + preserved remove(bytes32 key) { + requireInvariant consistencyIndex(to_uint256(length() - 1)); + } + } + +invariant consistencyKey(bytes32 key) + contains(key) => ( + _indexOf(key) > 0 && + _indexOf(key) <= length() && + key_at(to_uint256(_indexOf(key) - 1)) == key + ) + { + preserved remove(bytes32 otherKey) { + requireInvariant consistencyKey(otherKey); + requireInvariant atUniqueness( + to_uint256(_indexOf(key) - 1), + to_uint256(_indexOf(otherKey) - 1) + ); + } + } + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: state only changes by setting or removing elements │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule stateChange(env e, bytes32 key) { + require sanity(); + requireInvariant consistencyKey(key); + + uint256 lengthBefore = length(); + bool containsBefore = contains(key); + bytes32 valueBefore = tryGet_value(key); + + method f; + calldataarg args; + f(e, args); + + uint256 lengthAfter = length(); + bool containsAfter = contains(key); + bytes32 valueAfter = tryGet_value(key); + + assert lengthBefore != lengthAfter => ( + (f.selector == set(bytes32,bytes32).selector && lengthAfter == lengthBefore + 1) || + (f.selector == remove(bytes32).selector && lengthAfter == lengthBefore - 1) + ); + + assert containsBefore != containsAfter => ( + (f.selector == set(bytes32,bytes32).selector && containsAfter) || + (f.selector == remove(bytes32).selector && !containsAfter) + ); + + assert valueBefore != valueAfter => ( + (f.selector == set(bytes32,bytes32).selector && containsAfter) || + (f.selector == remove(bytes32).selector && !containsAfter && valueAfter == 0) + ); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: check liveness of view functions. │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule liveness_1(bytes32 key) { + requireInvariant consistencyKey(key); + + // contains never revert + bool contains = contains@withrevert(key); + assert !lastReverted; + + // tryGet never reverts (key) + tryGet_contains@withrevert(key); + assert !lastReverted; + + // tryGet never reverts (value) + tryGet_value@withrevert(key); + assert !lastReverted; + + // get reverts iff the key is not in the map + get@withrevert(key); + assert !lastReverted <=> contains; +} + +rule liveness_2(uint256 index) { + requireInvariant consistencyIndex(index); + + // length never revert + uint256 length = length@withrevert(); + assert !lastReverted; + + // key_at reverts iff the index is out of bound + key_at@withrevert(index); + assert !lastReverted <=> index < length; + + // value_at reverts iff the index is out of bound + value_at@withrevert(index); + assert !lastReverted <=> index < length; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: get and tryGet return the expected values. │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule getAndTryGet(bytes32 key) { + requireInvariant noValueIfNotContained(key); + + bool contained = contains(key); + bool tryContained = tryGet_contains(key); + bytes32 tryValue = tryGet_value(key); + bytes32 value = get@withrevert(key); // revert is not contained + + assert contained == tryContained; + assert contained => tryValue == value; + assert !contained => tryValue == 0; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: set key-value in EnumerableMap │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule set(bytes32 key, bytes32 value, bytes32 otherKey) { + require sanity(); + + uint256 lengthBefore = length(); + bool containsBefore = contains(key); + bool containsOtherBefore = contains(otherKey); + bytes32 otherValueBefore = tryGet_value(otherKey); + + bool added = set@withrevert(key, value); + bool success = !lastReverted; + + assert success && contains(key) && get(key) == value, + "liveness & immediate effect"; + + assert added <=> !containsBefore, + "return value: added iff not contained"; + + assert length() == lengthBefore + to_mathint(added ? 1 : 0), + "effect: length increases iff added"; + + assert added => (key_at(lengthBefore) == key && value_at(lengthBefore) == value), + "effect: add at the end"; + + assert containsOtherBefore != contains(otherKey) => (added && key == otherKey), + "side effect: other keys are not affected"; + + assert otherValueBefore != tryGet_value(otherKey) => key == otherKey, + "side effect: values attached to other keys are not affected"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: remove key from EnumerableMap │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule remove(bytes32 key, bytes32 otherKey) { + requireInvariant consistencyKey(key); + requireInvariant consistencyKey(otherKey); + + uint256 lengthBefore = length(); + bool containsBefore = contains(key); + bool containsOtherBefore = contains(otherKey); + bytes32 otherValueBefore = tryGet_value(otherKey); + + bool removed = remove@withrevert(key); + bool success = !lastReverted; + + assert success && !contains(key), + "liveness & immediate effect"; + + assert removed <=> containsBefore, + "return value: removed iff contained"; + + assert length() == lengthBefore - to_mathint(removed ? 1 : 0), + "effect: length decreases iff removed"; + + assert containsOtherBefore != contains(otherKey) => (removed && key == otherKey), + "side effect: other keys are not affected"; + + assert otherValueBefore != tryGet_value(otherKey) => key == otherKey, + "side effect: values attached to other keys are not affected"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: when adding a new key, the other keys remain in set, at the same index. │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule setEnumerability(bytes32 key, bytes32 value, uint256 index) { + require sanity(); + + bytes32 atKeyBefore = key_at(index); + bytes32 atValueBefore = value_at(index); + + set(key, value); + + bytes32 atKeyAfter = key_at@withrevert(index); + assert !lastReverted; + + bytes32 atValueAfter = value_at@withrevert(index); + assert !lastReverted; + + assert atKeyAfter == atKeyBefore; + assert atValueAfter != atValueBefore => ( + key == atKeyBefore && + value == atValueAfter + ); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: when removing a existing key, the other keys remain in set, at the same index (except for the last one). │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule removeEnumerability(bytes32 key, uint256 index) { + uint256 last = length() - 1; + + requireInvariant consistencyKey(key); + requireInvariant consistencyIndex(index); + requireInvariant consistencyIndex(last); + + bytes32 atKeyBefore = key_at(index); + bytes32 atValueBefore = value_at(index); + bytes32 lastKeyBefore = key_at(last); + bytes32 lastValueBefore = value_at(last); + + remove(key); + + // can't read last value & keys (length decreased) + bytes32 atKeyAfter = key_at@withrevert(index); + assert lastReverted <=> index == last; + + bytes32 atValueAfter = value_at@withrevert(index); + assert lastReverted <=> index == last; + + // One value that is allowed to change is if previous value was removed, + // in that case the last value before took its place. + assert ( + index != last && + atKeyBefore != atKeyAfter + ) => ( + atKeyBefore == key && + atKeyAfter == lastKeyBefore + ); + + assert ( + index != last && + atValueBefore != atValueAfter + ) => ( + atValueAfter == lastValueBefore + ); +} diff --git a/certora/specs/EnumerableSet.spec b/certora/specs/EnumerableSet.spec new file mode 100644 index 000000000..c94ba2437 --- /dev/null +++ b/certora/specs/EnumerableSet.spec @@ -0,0 +1,247 @@ +import "helpers.spec" + +methods { + // library + add(bytes32) returns (bool) envfree + remove(bytes32) returns (bool) envfree + contains(bytes32) returns (bool) envfree + length() returns (uint256) envfree + at_(uint256) returns (bytes32) envfree + + // FV + _indexOf(bytes32) returns (uint256) envfree +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Helpers │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +function sanity() returns bool { + return length() < max_uint256; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: All indexed keys are contained │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant indexedContained(uint256 index) + index < length() => contains(at_(index)) + { + preserved { + requireInvariant consistencyIndex(index); + requireInvariant consistencyIndex(to_uint256(length() - 1)); + } + } + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: A value can only be stored at a single location │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant atUniqueness(uint256 index1, uint256 index2) + index1 == index2 <=> at_(index1) == at_(index2) + { + preserved remove(bytes32 key) { + requireInvariant atUniqueness(index1, to_uint256(length() - 1)); + requireInvariant atUniqueness(index2, to_uint256(length() - 1)); + } + } + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: index <> key relationship is consistent │ +│ │ +│ Note that the two consistencyXxx invariants, put together, prove that at_ and _indexOf are inverse of one another. │ +│ This proves that we have a bijection between indices (the enumerability part) and keys (the entries that are added │ +│ and removed from the EnumerableSet). │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant consistencyIndex(uint256 index) + index < length() => _indexOf(at_(index)) == index + 1 + { + preserved remove(bytes32 key) { + requireInvariant consistencyIndex(to_uint256(length() - 1)); + } + } + +invariant consistencyKey(bytes32 key) + contains(key) => ( + _indexOf(key) > 0 && + _indexOf(key) <= length() && + at_(to_uint256(_indexOf(key) - 1)) == key + ) + { + preserved remove(bytes32 otherKey) { + requireInvariant consistencyKey(otherKey); + requireInvariant atUniqueness( + to_uint256(_indexOf(key) - 1), + to_uint256(_indexOf(otherKey) - 1) + ); + } + } + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: state only changes by adding or removing elements │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule stateChange(env e, bytes32 key) { + require sanity(); + requireInvariant consistencyKey(key); + + uint256 lengthBefore = length(); + bool containsBefore = contains(key); + + method f; + calldataarg args; + f(e, args); + + uint256 lengthAfter = length(); + bool containsAfter = contains(key); + + assert lengthBefore != lengthAfter => ( + (f.selector == add(bytes32).selector && lengthAfter == lengthBefore + 1) || + (f.selector == remove(bytes32).selector && lengthAfter == lengthBefore - 1) + ); + + assert containsBefore != containsAfter => ( + (f.selector == add(bytes32).selector && containsAfter) || + (f.selector == remove(bytes32).selector && containsBefore) + ); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: check liveness of view functions. │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule liveness_1(bytes32 key) { + requireInvariant consistencyKey(key); + + // contains never revert + contains@withrevert(key); + assert !lastReverted; +} + +rule liveness_2(uint256 index) { + requireInvariant consistencyIndex(index); + + // length never revert + uint256 length = length@withrevert(); + assert !lastReverted; + + // at reverts iff the index is out of bound + at_@withrevert(index); + assert !lastReverted <=> index < length; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: add key to EnumerableSet if not already contained │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule add(bytes32 key, bytes32 otherKey) { + require sanity(); + + uint256 lengthBefore = length(); + bool containsBefore = contains(key); + bool containsOtherBefore = contains(otherKey); + + bool added = add@withrevert(key); + bool success = !lastReverted; + + assert success && contains(key), + "liveness & immediate effect"; + + assert added <=> !containsBefore, + "return value: added iff not contained"; + + assert length() == lengthBefore + to_mathint(added ? 1 : 0), + "effect: length increases iff added"; + + assert added => at_(lengthBefore) == key, + "effect: add at the end"; + + assert containsOtherBefore != contains(otherKey) => (added && key == otherKey), + "side effect: other keys are not affected"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: remove key from EnumerableSet if already contained │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule remove(bytes32 key, bytes32 otherKey) { + requireInvariant consistencyKey(key); + requireInvariant consistencyKey(otherKey); + + uint256 lengthBefore = length(); + bool containsBefore = contains(key); + bool containsOtherBefore = contains(otherKey); + + bool removed = remove@withrevert(key); + bool success = !lastReverted; + + assert success && !contains(key), + "liveness & immediate effect"; + + assert removed <=> containsBefore, + "return value: removed iff contained"; + + assert length() == lengthBefore - to_mathint(removed ? 1 : 0), + "effect: length decreases iff removed"; + + assert containsOtherBefore != contains(otherKey) => (removed && key == otherKey), + "side effect: other keys are not affected"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: when adding a new key, the other keys remain in set, at the same index. │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule addEnumerability(bytes32 key, uint256 index) { + require sanity(); + + bytes32 atBefore = at_(index); + add(key); + bytes32 atAfter = at_@withrevert(index); + bool atAfterSuccess = !lastReverted; + + assert atAfterSuccess; + assert atBefore == atAfter; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: when removing a existing key, the other keys remain in set, at the same index (except for the last one). │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule removeEnumerability(bytes32 key, uint256 index) { + uint256 last = length() - 1; + + requireInvariant consistencyKey(key); + requireInvariant consistencyIndex(index); + requireInvariant consistencyIndex(last); + + bytes32 atBefore = at_(index); + bytes32 lastBefore = at_(last); + + remove(key); + + // can't read last value (length decreased) + bytes32 atAfter = at_@withrevert(index); + assert lastReverted <=> index == last; + + // One value that is allowed to change is if previous value was removed, + // in that case the last value before took its place. + assert ( + index != last && + atBefore != atAfter + ) => ( + atBefore == key && + atAfter == lastBefore + ); +} From 538655c3c06b615143141552b2d6d6f8515e4499 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Garc=C3=ADa?= Date: Wed, 3 May 2023 09:35:48 +0200 Subject: [PATCH 111/133] Add reentrancy test cases for ERC4626 (#4197) Co-authored-by: Hadrien Croubois Co-authored-by: Francisco Giordano --- contracts/mocks/ERC20Reentrant.sol | 43 +++++ test/token/ERC20/extensions/ERC4626.test.js | 175 ++++++++++++++++++++ 2 files changed, 218 insertions(+) create mode 100644 contracts/mocks/ERC20Reentrant.sol diff --git a/contracts/mocks/ERC20Reentrant.sol b/contracts/mocks/ERC20Reentrant.sol new file mode 100644 index 000000000..c0184b77b --- /dev/null +++ b/contracts/mocks/ERC20Reentrant.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "../token/ERC20/ERC20.sol"; +import "../token/ERC20/extensions/ERC4626.sol"; + +contract ERC20Reentrant is ERC20("TEST", "TST") { + enum Type { + No, + Before, + After + } + + Type private _reenterType; + address private _reenterTarget; + bytes private _reenterData; + + function scheduleReenter(Type when, address target, bytes calldata data) external { + _reenterType = when; + _reenterTarget = target; + _reenterData = data; + } + + function functionCall(address target, bytes memory data) public returns (bytes memory) { + return Address.functionCall(target, data); + } + + function _beforeTokenTransfer(address from, address to, uint256 amount) internal override { + if (_reenterType == Type.Before) { + _reenterType = Type.No; + functionCall(_reenterTarget, _reenterData); + } + super._beforeTokenTransfer(from, to, amount); + } + + function _afterTokenTransfer(address from, address to, uint256 amount) internal override { + super._afterTokenTransfer(from, to, amount); + if (_reenterType == Type.After) { + _reenterType = Type.No; + functionCall(_reenterTarget, _reenterData); + } + } +} diff --git a/test/token/ERC20/extensions/ERC4626.test.js b/test/token/ERC20/extensions/ERC4626.test.js index ee0998717..55b3e5d20 100644 --- a/test/token/ERC20/extensions/ERC4626.test.js +++ b/test/token/ERC20/extensions/ERC4626.test.js @@ -1,11 +1,14 @@ const { constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); const { expect } = require('chai'); +const { Enum } = require('../../../helpers/enums'); + const ERC20Decimals = artifacts.require('$ERC20DecimalsMock'); const ERC4626 = artifacts.require('$ERC4626'); const ERC4626OffsetMock = artifacts.require('$ERC4626OffsetMock'); const ERC4626FeesMock = artifacts.require('$ERC4626FeesMock'); const ERC20ExcessDecimalsMock = artifacts.require('ERC20ExcessDecimalsMock'); +const ERC20Reentrant = artifacts.require('$ERC20Reentrant'); contract('ERC4626', function (accounts) { const [holder, recipient, spender, other, user1, user2] = accounts; @@ -44,6 +47,178 @@ contract('ERC4626', function (accounts) { } }); + describe('reentrancy', async function () { + const reenterType = Enum('No', 'Before', 'After'); + + const amount = web3.utils.toBN(1000000000000000000); + const reenterAmount = web3.utils.toBN(1000000000); + let token; + let vault; + + beforeEach(async function () { + token = await ERC20Reentrant.new(); + // Use offset 1 so the rate is not 1:1 and we can't possibly confuse assets and shares + vault = await ERC4626OffsetMock.new('', '', token.address, 1); + // Funds and approval for tests + await token.$_mint(holder, amount); + await token.$_mint(other, amount); + await token.$_approve(holder, vault.address, constants.MAX_UINT256); + await token.$_approve(other, vault.address, constants.MAX_UINT256); + await token.$_approve(token.address, vault.address, constants.MAX_UINT256); + }); + + // During a `_deposit`, the vault does `transferFrom(depositor, vault, assets)` -> `_mint(receiver, shares)` + // such that a reentrancy BEFORE the transfer guarantees the price is kept the same. + // If the order of transfer -> mint is changed to mint -> transfer, the reentrancy could be triggered on an + // intermediate state in which the ratio of assets/shares has been decreased (more shares than assets). + it('correct share price is observed during reentrancy before deposit', async function () { + // mint token for deposit + await token.$_mint(token.address, reenterAmount); + + // Schedules a reentrancy from the token contract + await token.scheduleReenter( + reenterType.Before, + vault.address, + vault.contract.methods.deposit(reenterAmount, holder).encodeABI(), + ); + + // Initial share price + const sharesForDeposit = await vault.previewDeposit(amount, { from: holder }); + const sharesForReenter = await vault.previewDeposit(reenterAmount, { from: holder }); + + // Do deposit normally, triggering the _beforeTokenTransfer hook + const receipt = await vault.deposit(amount, holder, { from: holder }); + + // Main deposit event + await expectEvent(receipt, 'Deposit', { + sender: holder, + owner: holder, + assets: amount, + shares: sharesForDeposit, + }); + // Reentrant deposit event → uses the same price + await expectEvent(receipt, 'Deposit', { + sender: token.address, + owner: holder, + assets: reenterAmount, + shares: sharesForReenter, + }); + + // Assert prices is kept + const sharesAfter = await vault.previewDeposit(amount, { from: holder }); + expect(sharesForDeposit).to.be.bignumber.eq(sharesAfter); + }); + + // During a `_withdraw`, the vault does `_burn(owner, shares)` -> `transfer(receiver, assets)` + // such that a reentrancy AFTER the transfer guarantees the price is kept the same. + // If the order of burn -> transfer is changed to transfer -> burn, the reentrancy could be triggered on an + // intermediate state in which the ratio of shares/assets has been decreased (more assets than shares). + it('correct share price is observed during reentrancy after withdraw', async function () { + // Deposit into the vault: holder gets `amount` share, token.address gets `reenterAmount` shares + await vault.deposit(amount, holder, { from: holder }); + await vault.deposit(reenterAmount, token.address, { from: other }); + + // Schedules a reentrancy from the token contract + await token.scheduleReenter( + reenterType.After, + vault.address, + vault.contract.methods.withdraw(reenterAmount, holder, token.address).encodeABI(), + ); + + // Initial share price + const sharesForWithdraw = await vault.previewWithdraw(amount, { from: holder }); + const sharesForReenter = await vault.previewWithdraw(reenterAmount, { from: holder }); + + // Do withdraw normally, triggering the _afterTokenTransfer hook + const receipt = await vault.withdraw(amount, holder, holder, { from: holder }); + + // Main withdraw event + await expectEvent(receipt, 'Withdraw', { + sender: holder, + receiver: holder, + owner: holder, + assets: amount, + shares: sharesForWithdraw, + }); + // Reentrant withdraw event → uses the same price + await expectEvent(receipt, 'Withdraw', { + sender: token.address, + receiver: holder, + owner: token.address, + assets: reenterAmount, + shares: sharesForReenter, + }); + + // Assert price is kept + const sharesAfter = await vault.previewWithdraw(amount, { from: holder }); + expect(sharesForWithdraw).to.be.bignumber.eq(sharesAfter); + }); + + // Donate newly minted tokens to the vault during the reentracy causes the share price to increase. + // Still, the deposit that trigger the reentracy is not affected and get the previewed price. + // Further deposits will get a different price (getting fewer shares for the same amount of assets) + it('share price change during reentracy does not affect deposit', async function () { + // Schedules a reentrancy from the token contract that mess up the share price + await token.scheduleReenter( + reenterType.Before, + token.address, + token.contract.methods.$_mint(vault.address, reenterAmount).encodeABI(), + ); + + // Price before + const sharesBefore = await vault.previewDeposit(amount); + + // Deposit, triggering the _beforeTokenTransfer hook + const receipt = await vault.deposit(amount, holder, { from: holder }); + + // Price is as previewed + await expectEvent(receipt, 'Deposit', { + sender: holder, + owner: holder, + assets: amount, + shares: sharesBefore, + }); + + // Price was modified during reentrancy + const sharesAfter = await vault.previewDeposit(amount); + expect(sharesAfter).to.be.bignumber.lt(sharesBefore); + }); + + // Burn some tokens from the vault during the reentracy causes the share price to drop. + // Still, the withdraw that trigger the reentracy is not affected and get the previewed price. + // Further withdraw will get a different price (needing more shares for the same amount of assets) + it('share price change during reentracy does not affect withdraw', async function () { + await vault.deposit(amount, other, { from: other }); + await vault.deposit(amount, holder, { from: holder }); + + // Schedules a reentrancy from the token contract that mess up the share price + await token.scheduleReenter( + reenterType.After, + token.address, + token.contract.methods.$_burn(vault.address, reenterAmount).encodeABI(), + ); + + // Price before + const sharesBefore = await vault.previewWithdraw(amount); + + // Withdraw, triggering the _afterTokenTransfer hook + const receipt = await vault.withdraw(amount, holder, holder, { from: holder }); + + // Price is as previewed + await expectEvent(receipt, 'Withdraw', { + sender: holder, + receiver: holder, + owner: holder, + assets: amount, + shares: sharesBefore, + }); + + // Price was modified during reentrancy + const sharesAfter = await vault.previewWithdraw(amount); + expect(sharesAfter).to.be.bignumber.gt(sharesBefore); + }); + }); + for (const offset of [0, 6, 18].map(web3.utils.toBN)) { const parseToken = token => web3.utils.toBN(10).pow(decimals).muln(token); const parseShare = share => web3.utils.toBN(10).pow(decimals.add(offset)).muln(share); From 10022da83d75a5ae0cae5222dced463a6678cf61 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Wed, 3 May 2023 16:13:42 +0200 Subject: [PATCH 112/133] Disable automatic formal verification workflow on push (#4208) --- .github/workflows/formal-verification.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/formal-verification.yml b/.github/workflows/formal-verification.yml index f94152a52..ae5eba006 100644 --- a/.github/workflows/formal-verification.yml +++ b/.github/workflows/formal-verification.yml @@ -1,10 +1,6 @@ name: formal verification on: - push: - branches: - - master - - release-v* pull_request: types: - opened From a7ee03565b4ee14265f4406f9e38a04e0143656f Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Wed, 3 May 2023 16:34:14 +0200 Subject: [PATCH 113/133] Move certora helpers to a dedicated folder (#4211) --- certora/specs/AccessControl.spec | 2 +- certora/specs/DoubleEndedQueue.spec | 36 ++++++++++++------------ certora/specs/ERC20.spec | 2 +- certora/specs/ERC20FlashMint.spec | 2 +- certora/specs/ERC20Wrapper.spec | 2 +- certora/specs/ERC721.spec | 2 +- certora/specs/EnumerableMap.spec | 2 +- certora/specs/EnumerableSet.spec | 2 +- certora/specs/Initializable.spec | 2 +- certora/specs/Ownable.spec | 2 +- certora/specs/Ownable2Step.spec | 2 +- certora/specs/Pausable.spec | 8 +++--- certora/specs/TimelockController.spec | 2 +- certora/specs/{ => helpers}/helpers.spec | 0 14 files changed, 33 insertions(+), 33 deletions(-) rename certora/specs/{ => helpers}/helpers.spec (100%) diff --git a/certora/specs/AccessControl.spec b/certora/specs/AccessControl.spec index 35927c5d3..81b6d3604 100644 --- a/certora/specs/AccessControl.spec +++ b/certora/specs/AccessControl.spec @@ -1,4 +1,4 @@ -import "helpers.spec" +import "helpers/helpers.spec" import "methods/IAccessControl.spec" /* diff --git a/certora/specs/DoubleEndedQueue.spec b/certora/specs/DoubleEndedQueue.spec index 2412b4cc8..2a196772d 100644 --- a/certora/specs/DoubleEndedQueue.spec +++ b/certora/specs/DoubleEndedQueue.spec @@ -1,4 +1,4 @@ -import "helpers.spec" +import "helpers/helpers.spec" methods { pushFront(bytes32) envfree @@ -10,7 +10,7 @@ methods { // exposed for FV begin() returns (int128) envfree end() returns (int128) envfree - + // view length() returns (uint256) envfree empty() returns (bool) envfree @@ -35,7 +35,7 @@ function max_int128() returns mathint { // Could be broken in theory, but not in practice function boundedQueue() returns bool { - return + return max_int128() > to_mathint(end()) && min_int128() < to_mathint(begin()); } @@ -78,11 +78,11 @@ invariant emptiness() invariant queueEndings() at_(length() - 1) == back() && at_(0) == front() filtered { f -> !f.isView } - { - preserved { - requireInvariant boundariesConsistency(); - require boundedQueue(); - } + { + preserved { + requireInvariant boundariesConsistency(); + require boundedQueue(); + } } /* @@ -94,12 +94,12 @@ rule pushFront(bytes32 value) { require boundedQueue(); uint256 lengthBefore = length(); - + pushFront@withrevert(value); - + // liveness assert !lastReverted, "never reverts"; - + // effect assert front() == value, "front set to value"; assert length() == lengthBefore + 1, "queue extended"; @@ -134,12 +134,12 @@ rule pushBack(bytes32 value) { require boundedQueue(); uint256 lengthBefore = length(); - + pushBack@withrevert(value); - + // liveness assert !lastReverted, "never reverts"; - + // effect assert back() == value, "back set to value"; assert length() == lengthBefore + 1, "queue increased"; @@ -205,7 +205,7 @@ rule popFrontConsistency(uint256 index) { // try to read value bytes32 after = at_@withrevert(index - 1); - + assert !lastReverted, "value still exists in the queue"; assert before == after, "values are offset and not modified"; } @@ -250,7 +250,7 @@ rule popBackConsistency(uint256 index) { // try to read value bytes32 after = at_@withrevert(index); - + assert !lastReverted, "value still exists in the queue"; assert before == after, "values are offset and not modified"; } @@ -262,10 +262,10 @@ rule popBackConsistency(uint256 index) { */ rule clear { clear@withrevert(); - + // liveness assert !lastReverted, "never reverts"; - + // effect assert length() == 0, "sets length to 0"; } diff --git a/certora/specs/ERC20.spec b/certora/specs/ERC20.spec index 85f95e706..3bd2b38ba 100644 --- a/certora/specs/ERC20.spec +++ b/certora/specs/ERC20.spec @@ -1,4 +1,4 @@ -import "helpers.spec" +import "helpers/helpers.spec" import "methods/IERC20.spec" import "methods/IERC2612.spec" diff --git a/certora/specs/ERC20FlashMint.spec b/certora/specs/ERC20FlashMint.spec index 64d97342a..70a7c0795 100644 --- a/certora/specs/ERC20FlashMint.spec +++ b/certora/specs/ERC20FlashMint.spec @@ -1,4 +1,4 @@ -import "helpers.spec" +import "helpers/helpers.spec" import "methods/IERC20.spec" import "methods/IERC3156.spec" diff --git a/certora/specs/ERC20Wrapper.spec b/certora/specs/ERC20Wrapper.spec index c10173766..badfa7a28 100644 --- a/certora/specs/ERC20Wrapper.spec +++ b/certora/specs/ERC20Wrapper.spec @@ -1,4 +1,4 @@ -import "helpers.spec" +import "helpers/helpers.spec" import "ERC20.spec" methods { diff --git a/certora/specs/ERC721.spec b/certora/specs/ERC721.spec index 48503469b..9db13f45c 100644 --- a/certora/specs/ERC721.spec +++ b/certora/specs/ERC721.spec @@ -1,4 +1,4 @@ -import "helpers.spec" +import "helpers/helpers.spec" import "methods/IERC721.spec" methods { diff --git a/certora/specs/EnumerableMap.spec b/certora/specs/EnumerableMap.spec index 56ef854c6..dea5d85ec 100644 --- a/certora/specs/EnumerableMap.spec +++ b/certora/specs/EnumerableMap.spec @@ -1,4 +1,4 @@ -import "helpers.spec" +import "helpers/helpers.spec" methods { // library diff --git a/certora/specs/EnumerableSet.spec b/certora/specs/EnumerableSet.spec index c94ba2437..d63c556aa 100644 --- a/certora/specs/EnumerableSet.spec +++ b/certora/specs/EnumerableSet.spec @@ -1,4 +1,4 @@ -import "helpers.spec" +import "helpers/helpers.spec" methods { // library diff --git a/certora/specs/Initializable.spec b/certora/specs/Initializable.spec index 1ba8d54e8..0e0b1b714 100644 --- a/certora/specs/Initializable.spec +++ b/certora/specs/Initializable.spec @@ -1,4 +1,4 @@ -import "helpers.spec" +import "helpers/helpers.spec" methods { // initialize, reinitialize, disable diff --git a/certora/specs/Ownable.spec b/certora/specs/Ownable.spec index 4fdfeb09c..4bf9e3005 100644 --- a/certora/specs/Ownable.spec +++ b/certora/specs/Ownable.spec @@ -1,4 +1,4 @@ -import "helpers.spec" +import "helpers/helpers.spec" import "methods/IOwnable.spec" methods { diff --git a/certora/specs/Ownable2Step.spec b/certora/specs/Ownable2Step.spec index 70c520a03..47b1b8d75 100644 --- a/certora/specs/Ownable2Step.spec +++ b/certora/specs/Ownable2Step.spec @@ -1,4 +1,4 @@ -import "helpers.spec" +import "helpers/helpers.spec" import "methods/IOwnable2Step.spec" methods { diff --git a/certora/specs/Pausable.spec b/certora/specs/Pausable.spec index e49293ffc..aea38003f 100644 --- a/certora/specs/Pausable.spec +++ b/certora/specs/Pausable.spec @@ -1,4 +1,4 @@ -import "helpers.spec" +import "helpers/helpers.spec" methods { paused() returns (bool) envfree @@ -22,7 +22,7 @@ rule pause(env e) { bool success = !lastReverted; bool pausedAfter = paused(); - + // liveness assert success <=> !pausedBefore, "works if and only if the contract was not paused before"; @@ -44,7 +44,7 @@ rule unpause(env e) { bool success = !lastReverted; bool pausedAfter = paused(); - + // liveness assert success <=> pausedBefore, "works if and only if the contract was paused before"; @@ -71,7 +71,7 @@ rule whenPaused(env e) { */ rule whenNotPaused(env e) { require nonpayable(e); - + onlyWhenNotPaused@withrevert(e); assert !lastReverted <=> !paused(), "works if and only if the contract is not paused"; } diff --git a/certora/specs/TimelockController.spec b/certora/specs/TimelockController.spec index e140c11de..05ecb1340 100644 --- a/certora/specs/TimelockController.spec +++ b/certora/specs/TimelockController.spec @@ -1,4 +1,4 @@ -import "helpers.spec" +import "helpers/helpers.spec" import "methods/IAccessControl.spec" methods { diff --git a/certora/specs/helpers.spec b/certora/specs/helpers/helpers.spec similarity index 100% rename from certora/specs/helpers.spec rename to certora/specs/helpers/helpers.spec From 9e8b74a0e2c8a6e87f7fa88318f15017d4b14524 Mon Sep 17 00:00:00 2001 From: Francisco Date: Thu, 4 May 2023 14:33:57 +0100 Subject: [PATCH 114/133] Add more test cases for EIP712 (#4212) --- contracts/utils/cryptography/EIP712.sol | 2 + test/utils/cryptography/EIP712.test.js | 137 +++++++++++++++--------- 2 files changed, 87 insertions(+), 52 deletions(-) diff --git a/contracts/utils/cryptography/EIP712.sol b/contracts/utils/cryptography/EIP712.sol index e06d0066b..56dfceaf4 100644 --- a/contracts/utils/cryptography/EIP712.sol +++ b/contracts/utils/cryptography/EIP712.sol @@ -111,6 +111,8 @@ abstract contract EIP712 is IERC5267 { /** * @dev See {EIP-5267}. + * + * _Available since v4.9._ */ function eip712Domain() public diff --git a/test/utils/cryptography/EIP712.test.js b/test/utils/cryptography/EIP712.test.js index f12f22673..52e322d3d 100644 --- a/test/utils/cryptography/EIP712.test.js +++ b/test/utils/cryptography/EIP712.test.js @@ -6,65 +6,98 @@ const { getChainId } = require('../../helpers/chainid'); const { mapValues } = require('../../helpers/map-values'); const EIP712Verifier = artifacts.require('$EIP712Verifier'); +const Clones = artifacts.require('$Clones'); contract('EIP712', function (accounts) { const [mailTo] = accounts; - const name = 'A Name'; - const version = '1'; + const shortName = 'A Name'; + const shortVersion = '1'; - beforeEach('deploying', async function () { - this.eip712 = await EIP712Verifier.new(name, version); + const longName = 'A'.repeat(40); + const longVersion = 'B'.repeat(40); - this.domain = { - name, - version, - chainId: await getChainId(), - verifyingContract: this.eip712.address, - }; - this.domainType = domainType(this.domain); - }); + const cases = [ + ['short', shortName, shortVersion], + ['long', longName, longVersion], + ]; - describe('domain separator', function () { - it('is internally available', async function () { - const expected = await domainSeparator(this.domain); + for (const [shortOrLong, name, version] of cases) { + describe(`with ${shortOrLong} name and version`, function () { + beforeEach('deploying', async function () { + this.eip712 = await EIP712Verifier.new(name, version); - expect(await this.eip712.$_domainSeparatorV4()).to.equal(expected); + this.domain = { + name, + version, + chainId: await getChainId(), + verifyingContract: this.eip712.address, + }; + this.domainType = domainType(this.domain); + }); + + describe('domain separator', function () { + it('is internally available', async function () { + const expected = await domainSeparator(this.domain); + + expect(await this.eip712.$_domainSeparatorV4()).to.equal(expected); + }); + + it("can be rebuilt using EIP-5267's eip712Domain", async function () { + const rebuildDomain = await getDomain(this.eip712); + expect(mapValues(rebuildDomain, String)).to.be.deep.equal(mapValues(this.domain, String)); + }); + + if (shortOrLong === 'short') { + // Long strings are in storage, and the proxy will not be properly initialized unless + // the upgradeable contract variant is used and the initializer is invoked. + + it('adjusts when behind proxy', async function () { + const factory = await Clones.new(); + const cloneReceipt = await factory.$clone(this.eip712.address); + const cloneAddress = cloneReceipt.logs.find(({ event }) => event === 'return$clone').args.instance; + const clone = new EIP712Verifier(cloneAddress); + + const cloneDomain = { ...this.domain, verifyingContract: clone.address }; + + const expectedSeparator = await domainSeparator(cloneDomain); + expect(await clone.$_domainSeparatorV4()).to.equal(expectedSeparator); + + const reportedDomain = await getDomain(clone); + expect(mapValues(reportedDomain, String)).to.be.deep.equal(mapValues(cloneDomain, String)); + }); + } + }); + + it('hash digest', async function () { + const structhash = web3.utils.randomHex(32); + expect(await this.eip712.$_hashTypedDataV4(structhash)).to.be.equal(hashTypedData(this.domain, structhash)); + }); + + it('digest', async function () { + const message = { + to: mailTo, + contents: 'very interesting', + }; + + const data = { + types: { + EIP712Domain: this.domainType, + Mail: [ + { name: 'to', type: 'address' }, + { name: 'contents', type: 'string' }, + ], + }, + domain: this.domain, + primaryType: 'Mail', + message, + }; + + const wallet = Wallet.generate(); + const signature = ethSigUtil.signTypedMessage(wallet.getPrivateKey(), { data }); + + await this.eip712.verify(signature, wallet.getAddressString(), message.to, message.contents); + }); }); - - it("can be rebuilt using EIP-5267's eip712Domain", async function () { - const rebuildDomain = await getDomain(this.eip712); - expect(mapValues(rebuildDomain, String)).to.be.deep.equal(mapValues(this.domain, String)); - }); - }); - - it('hash digest', async function () { - const structhash = web3.utils.randomHex(32); - expect(await this.eip712.$_hashTypedDataV4(structhash)).to.be.equal(hashTypedData(this.domain, structhash)); - }); - - it('digest', async function () { - const message = { - to: mailTo, - contents: 'very interesting', - }; - - const data = { - types: { - EIP712Domain: this.domainType, - Mail: [ - { name: 'to', type: 'address' }, - { name: 'contents', type: 'string' }, - ], - }, - domain: this.domain, - primaryType: 'Mail', - message, - }; - - const wallet = Wallet.generate(); - const signature = ethSigUtil.signTypedMessage(wallet.getPrivateKey(), { data }); - - await this.eip712.verify(signature, wallet.getAddressString(), message.to, message.contents); - }); + } }); From 8b2ed0f5706fe1a7ab6ade84b27bf875dc611fda Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Thu, 4 May 2023 18:54:22 +0200 Subject: [PATCH 115/133] Fix early reporting of FV prover's output (#4213) Co-authored-by: Francisco --- certora/run.js | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/certora/run.js b/certora/run.js index 2dc7d0181..fdee42d2e 100755 --- a/certora/run.js +++ b/certora/run.js @@ -73,15 +73,18 @@ async function runCertora(spec, contract, files, options = []) { child.stdout.pipe(stream, { end: false }); child.stderr.pipe(stream, { end: false }); - // as soon as we have a jobStatus link, print it + // as soon as we have a job id, print the output link stream.on('data', function logStatusUrl(data) { - const urls = data.toString('utf8').match(/https?:\S*/g); - for (const url of urls ?? []) { - if (url.includes('/jobStatus/')) { - console.error(`[${spec}] ${url.replace('/jobStatus/', '/output/')}`); - stream.off('data', logStatusUrl); - break; - } + const { '-DjobId': jobId, '-DuserId': userId } = Object.fromEntries( + data + .toString('utf8') + .match(/-D\S+=\S+/g) + ?.map(s => s.split('=')) || [], + ); + + if (jobId && userId) { + console.error(`[${spec}] https://prover.certora.com/output/${userId}/${jobId}/`); + stream.off('data', logStatusUrl); } }); @@ -98,7 +101,7 @@ async function runCertora(spec, contract, files, options = []) { stream.end(); // write results in markdown format - writeEntry(spec, contract, code || signal, (await output).match(/https:\S*/)?.[0]); + writeEntry(spec, contract, code || signal, (await output).match(/https:\/\/prover.certora.com\/output\/\S*/)?.[0]); // write all details console.error(`+ certoraRun ${args.join(' ')}\n` + (await output)); @@ -136,8 +139,8 @@ function writeEntry(spec, contract, success, url) { spec, contract, success ? ':x:' : ':heavy_check_mark:', + url ? `[link](${url?.replace('/output/', '/jobStatus/')})` : 'error', url ? `[link](${url})` : 'error', - url ? `[link](${url?.replace('/jobStatus/', '/output/')})` : 'error', ), ); } From dcba9f995ffa83433cc523a8e3d1fcfeac426377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Garc=C3=ADa?= Date: Fri, 5 May 2023 21:27:43 +0200 Subject: [PATCH 116/133] Add AccessControlDefaultAdminRules FV (#4180) Co-authored-by: Hadrien Croubois Co-authored-by: Francisco --- .../AccessControlDefaultAdminRulesHarness.sol | 47 ++ certora/specs.json | 5 + certora/specs/AccessControl.spec | 20 +- .../specs/AccessControlDefaultAdminRules.spec | 500 ++++++++++++++++++ .../IAccessControlDefaultAdminRules.spec | 36 ++ certora/specs/methods/IERC5313.spec | 3 + 6 files changed, 603 insertions(+), 8 deletions(-) create mode 100644 certora/harnesses/AccessControlDefaultAdminRulesHarness.sol create mode 100644 certora/specs/AccessControlDefaultAdminRules.spec create mode 100644 certora/specs/methods/IAccessControlDefaultAdminRules.spec create mode 100644 certora/specs/methods/IERC5313.spec diff --git a/certora/harnesses/AccessControlDefaultAdminRulesHarness.sol b/certora/harnesses/AccessControlDefaultAdminRulesHarness.sol new file mode 100644 index 000000000..29fd3a709 --- /dev/null +++ b/certora/harnesses/AccessControlDefaultAdminRulesHarness.sol @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../patched/access/AccessControlDefaultAdminRules.sol"; + +contract AccessControlDefaultAdminRulesHarness is AccessControlDefaultAdminRules { + uint48 private _delayIncreaseWait; + + constructor( + uint48 initialDelay, + address initialDefaultAdmin, + uint48 delayIncreaseWait + ) AccessControlDefaultAdminRules(initialDelay, initialDefaultAdmin) { + _delayIncreaseWait = delayIncreaseWait; + } + + // FV + function pendingDefaultAdmin_() external view returns (address) { + (address newAdmin, ) = pendingDefaultAdmin(); + return newAdmin; + } + + function pendingDefaultAdminSchedule_() external view returns (uint48) { + (, uint48 schedule) = pendingDefaultAdmin(); + return schedule; + } + + function pendingDelay_() external view returns (uint48) { + (uint48 newDelay, ) = pendingDefaultAdminDelay(); + return newDelay; + } + + function pendingDelaySchedule_() external view returns (uint48) { + (, uint48 schedule) = pendingDefaultAdminDelay(); + return schedule; + } + + function delayChangeWait_(uint48 newDelay) external view returns (uint48) { + return _delayChangeWait(newDelay); + } + + // Overrides + function defaultAdminDelayIncreaseWait() public view override returns (uint48) { + return _delayIncreaseWait; + } +} diff --git a/certora/specs.json b/certora/specs.json index 6f8f57bdf..3e5acb568 100644 --- a/certora/specs.json +++ b/certora/specs.json @@ -9,6 +9,11 @@ "contract": "AccessControlHarness", "files": ["certora/harnesses/AccessControlHarness.sol"] }, + { + "spec": "AccessControlDefaultAdminRules", + "contract": "AccessControlDefaultAdminRulesHarness", + "files": ["certora/harnesses/AccessControlDefaultAdminRulesHarness.sol"] + }, { "spec": "DoubleEndedQueue", "contract": "DoubleEndedQueueHarness", diff --git a/certora/specs/AccessControl.spec b/certora/specs/AccessControl.spec index 81b6d3604..cd5af2a99 100644 --- a/certora/specs/AccessControl.spec +++ b/certora/specs/AccessControl.spec @@ -1,13 +1,20 @@ import "helpers/helpers.spec" import "methods/IAccessControl.spec" +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Definitions │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +definition DEFAULT_ADMIN_ROLE() returns bytes32 = 0x0000000000000000000000000000000000000000000000000000000000000000; + /* ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ Identify entrypoints: only grantRole, revokeRole and renounceRole can alter permissions │ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ */ -rule onlyGrantCanGrant(env e, bytes32 role, address account) { - method f; calldataarg args; +rule onlyGrantCanGrant(env e, method f, bytes32 role, address account) { + calldataarg args; bool hasRoleBefore = hasRole(role, account); f(e, args); @@ -34,10 +41,9 @@ rule onlyGrantCanGrant(env e, bytes32 role, address account) { │ Function correctness: grantRole only affects the specified user/role combo │ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ */ -rule grantRoleEffect(env e) { +rule grantRoleEffect(env e, bytes32 role) { require nonpayable(e); - bytes32 role; bytes32 otherRole; address account; address otherAccount; @@ -65,10 +71,9 @@ rule grantRoleEffect(env e) { │ Function correctness: revokeRole only affects the specified user/role combo │ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ */ -rule revokeRoleEffect(env e) { +rule revokeRoleEffect(env e, bytes32 role) { require nonpayable(e); - bytes32 role; bytes32 otherRole; address account; address otherAccount; @@ -96,10 +101,9 @@ rule revokeRoleEffect(env e) { │ Function correctness: renounceRole only affects the specified user/role combo │ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ */ -rule renounceRoleEffect(env e) { +rule renounceRoleEffect(env e, bytes32 role) { require nonpayable(e); - bytes32 role; bytes32 otherRole; address account; address otherAccount; diff --git a/certora/specs/AccessControlDefaultAdminRules.spec b/certora/specs/AccessControlDefaultAdminRules.spec new file mode 100644 index 000000000..a4baa1871 --- /dev/null +++ b/certora/specs/AccessControlDefaultAdminRules.spec @@ -0,0 +1,500 @@ +import "helpers/helpers.spec" +import "methods/IAccessControlDefaultAdminRules.spec" +import "methods/IAccessControl.spec" +import "AccessControl.spec" + +use rule onlyGrantCanGrant filtered { + f -> f.selector != acceptDefaultAdminTransfer().selector +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Helpers │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ + +function max_uint48() returns mathint { + return (1 << 48) - 1; +} + +function nonZeroAccount(address account) returns bool { + return account != 0; +} + +function timeSanity(env e) returns bool { + return + e.block.timestamp > 0 && // Avoids 0 schedules + e.block.timestamp + defaultAdminDelay(e) < max_uint48(); +} + +function delayChangeWaitSanity(env e, uint48 newDelay) returns bool { + return e.block.timestamp + delayChangeWait_(e, newDelay) < max_uint48(); +} + +function isSet(uint48 schedule) returns bool { + return schedule != 0; +} + +function hasPassed(env e, uint48 schedule) returns bool { + return schedule < e.block.timestamp; +} + +function min(uint48 a, uint48 b) returns mathint { + return a < b ? a : b; +} + +function increasingDelaySchedule(env e, uint48 newDelay) returns mathint { + return e.block.timestamp + min(newDelay, defaultAdminDelayIncreaseWait()); +} + +function decreasingDelaySchedule(env e, uint48 newDelay) returns mathint { + return e.block.timestamp + defaultAdminDelay(e) - newDelay; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: defaultAdmin holds the DEFAULT_ADMIN_ROLE │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant defaultAdminConsistency(address account) + defaultAdmin() == account <=> hasRole(DEFAULT_ADMIN_ROLE(), account) + { + preserved { + // defaultAdmin() returns the zero address when there's no default admin + require nonZeroAccount(account); + } + } + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: Only one account holds the DEFAULT_ADMIN_ROLE │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant singleDefaultAdmin(address account, address another) + hasRole(DEFAULT_ADMIN_ROLE(), account) && hasRole(DEFAULT_ADMIN_ROLE(), another) => another == account + // We filter here because we couldn't find a way to force Certora to have an initial state with + // only one DEFAULT_ADMIN_ROLE enforced, so a counter example is a different default admin since inception + // triggering the transfer, which is known to be impossible by definition. + filtered { f -> f.selector != acceptDefaultAdminTransfer().selector } + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: DEFAULT_ADMIN_ROLE's admin is always DEFAULT_ADMIN_ROLE │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant defaultAdminRoleAdminConsistency() + getRoleAdmin(DEFAULT_ADMIN_ROLE()) == DEFAULT_ADMIN_ROLE() + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: owner is the defaultAdmin │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant ownerConsistency() + defaultAdmin() == owner() + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: revokeRole only affects the specified user/role combo │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule revokeRoleEffect(env e, bytes32 role) { + require nonpayable(e); + + bytes32 otherRole; + address account; + address otherAccount; + + bool isCallerAdmin = hasRole(getRoleAdmin(role), e.msg.sender); + bool hasOtherRoleBefore = hasRole(otherRole, otherAccount); + + revokeRole@withrevert(e, role, account); + bool success = !lastReverted; + + bool hasOtherRoleAfter = hasRole(otherRole, otherAccount); + + // liveness + assert success <=> isCallerAdmin && role != DEFAULT_ADMIN_ROLE(), + "roles can only be revoked by their owner except for the default admin role"; + + // effect + assert success => !hasRole(role, account), "role is revoked"; + + // no side effect + assert hasOtherRoleBefore != hasOtherRoleAfter => (role == otherRole && account == otherAccount), + "no other role is affected"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: renounceRole only affects the specified user/role combo │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule renounceRoleEffect(env e, bytes32 role) { + require nonpayable(e); + + bytes32 otherRole; + address account; + address otherAccount; + + bool hasOtherRoleBefore = hasRole(otherRole, otherAccount); + uint48 scheduleBefore = pendingDefaultAdminSchedule_(); + address pendingAdminBefore = pendingDefaultAdmin_(); + + renounceRole@withrevert(e, role, account); + bool success = !lastReverted; + + bool hasOtherRoleAfter = hasRole(otherRole, otherAccount); + + // liveness + assert success <=> ( + account == e.msg.sender && + ( + ( + role != DEFAULT_ADMIN_ROLE() + ) || ( + role == DEFAULT_ADMIN_ROLE() && + pendingAdminBefore == 0 && + isSet(scheduleBefore) && + hasPassed(e, scheduleBefore) + ) + ) + ), "an account only can renounce by itself with a delay for the default admin role"; + + // effect + assert success => !hasRole(role, account), "role is renounced"; + + // no side effect + assert hasOtherRoleBefore != hasOtherRoleAfter => (role == otherRole && account == otherAccount), + "no other role is affected"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: defaultAdmin is only affected by accepting an admin transfer or renoucing │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule noDefaultAdminChange(env e, method f, calldataarg args) { + require nonZeroAccount(e.msg.sender); + requireInvariant defaultAdminConsistency(defaultAdmin()); + requireInvariant singleDefaultAdmin(e.msg.sender, defaultAdmin()); + + address adminBefore = defaultAdmin(); + f(e, args); + address adminAfter = defaultAdmin(); + + assert adminBefore != adminAfter => ( + f.selector == acceptDefaultAdminTransfer().selector || + f.selector == renounceRole(bytes32,address).selector + ), "default admin is only affected by accepting an admin transfer or renoucing"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: pendingDefaultAdmin is only affected by beginning, accepting or canceling an admin transfer │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule noPendingDefaultAdminChange(env e, method f, calldataarg args) { + requireInvariant defaultAdminConsistency(defaultAdmin()); + requireInvariant singleDefaultAdmin(e.msg.sender, defaultAdmin()); + + address pendingAdminBefore = pendingDefaultAdmin_(); + address scheduleBefore = pendingDefaultAdminSchedule_(); + f(e, args); + address pendingAdminAfter = pendingDefaultAdmin_(); + address scheduleAfter = pendingDefaultAdminSchedule_(); + + assert ( + pendingAdminBefore != pendingAdminAfter || + scheduleBefore != scheduleAfter + ) => ( + f.selector == beginDefaultAdminTransfer(address).selector || + f.selector == acceptDefaultAdminTransfer().selector || + f.selector == cancelDefaultAdminTransfer().selector + ), "pending admin and its schedule is only affected by beginning, accepting or cancelling an admin transfer"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: defaultAdminDelay can't be changed atomically by any function │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule noDefaultAdminDelayChange(env e, method f, calldataarg args) { + uint48 delayBefore = defaultAdminDelay(e); + f(e, args); + uint48 delayAfter = defaultAdminDelay(e); + + assert delayBefore == delayAfter, "delay can't be changed atomically by any function"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: pendingDefaultAdminDelay is only affected by changeDefaultAdminDelay or rollbackDefaultAdminDelay │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule noPendingDefaultAdminDelayChange(env e, method f, calldataarg args) { + uint48 pendingDelayBefore = pendingDelay_(e); + f(e, args); + uint48 pendingDelayAfter = pendingDelay_(e); + + assert pendingDelayBefore != pendingDelayAfter => ( + f.selector == changeDefaultAdminDelay(uint48).selector || + f.selector == rollbackDefaultAdminDelay().selector + ), "pending delay is only affected by changeDefaultAdminDelay or rollbackDefaultAdminDelay"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: defaultAdminDelayIncreaseWait can't be changed atomically by any function │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule noDefaultAdminDelayIncreaseWaitChange(env e, method f, calldataarg args) { + uint48 delayIncreaseWaitBefore = defaultAdminDelayIncreaseWait(); + f(e, args); + uint48 delayIncreaseWaitAfter = defaultAdminDelayIncreaseWait(); + + assert delayIncreaseWaitBefore == delayIncreaseWaitAfter, + "delay increase wait can't be changed atomically by any function"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: beginDefaultAdminTransfer sets a pending default admin and its schedule │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule beginDefaultAdminTransfer(env e, address newAdmin) { + require nonpayable(e); + require timeSanity(e); + requireInvariant defaultAdminConsistency(defaultAdmin()); + requireInvariant singleDefaultAdmin(e.msg.sender, defaultAdmin()); + + beginDefaultAdminTransfer@withrevert(e, newAdmin); + bool success = !lastReverted; + + // liveness + assert success <=> e.msg.sender == defaultAdmin(), + "only the current default admin can begin a transfer"; + + // effect + assert success => pendingDefaultAdmin_() == newAdmin, + "pending default admin is set"; + assert success => pendingDefaultAdminSchedule_() == e.block.timestamp + defaultAdminDelay(e), + "pending default admin delay is set"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: A default admin can't change in less than the applied schedule │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule pendingDefaultAdminDelayEnforced(env e1, env e2, method f, calldataarg args, address newAdmin) { + require e1.block.timestamp < e2.block.timestamp; + + uint48 delayBefore = defaultAdminDelay(e1); + address adminBefore = defaultAdmin(); + // There might be a better way to generalize this without requiring `beginDefaultAdminTransfer`, but currently + // it's the only way in which we can attest that only `delayBefore` has passed before a change. + beginDefaultAdminTransfer(e1, newAdmin); + f(e2, args); + address adminAfter = defaultAdmin(); + + assert adminAfter == newAdmin => ((e2.block.timestamp >= e1.block.timestamp + delayBefore) || adminBefore == newAdmin), + "A delay can't change in less than applied schedule"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: acceptDefaultAdminTransfer updates defaultAdmin resetting the pending admin and its schedule │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule acceptDefaultAdminTransfer(env e) { + require nonpayable(e); + requireInvariant defaultAdminConsistency(defaultAdmin()); + requireInvariant singleDefaultAdmin(e.msg.sender, defaultAdmin()); + + address pendingAdminBefore = pendingDefaultAdmin_(); + uint48 scheduleAfter = pendingDefaultAdminSchedule_(); + + acceptDefaultAdminTransfer@withrevert(e); + bool success = !lastReverted; + + // liveness + assert success <=> e.msg.sender == pendingAdminBefore && isSet(scheduleAfter) && hasPassed(e, scheduleAfter), + "only the pending default admin can accept the role after the schedule has been set and passed"; + + // effect + assert success => defaultAdmin() == pendingAdminBefore, + "Default admin is set to the previous pending default admin"; + assert success => pendingDefaultAdmin_() == 0, + "Pending default admin is reset"; + assert success => pendingDefaultAdminSchedule_() == 0, + "Pending default admin delay is reset"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: cancelDefaultAdminTransfer resets pending default admin and its schedule │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule cancelDefaultAdminTransfer(env e) { + require nonpayable(e); + requireInvariant defaultAdminConsistency(defaultAdmin()); + requireInvariant singleDefaultAdmin(e.msg.sender, defaultAdmin()); + + cancelDefaultAdminTransfer@withrevert(e); + bool success = !lastReverted; + + // liveness + assert success <=> e.msg.sender == defaultAdmin(), + "only the current default admin can cancel a transfer"; + + // effect + assert success => pendingDefaultAdmin_() == 0, + "Pending default admin is reset"; + assert success => pendingDefaultAdminSchedule_() == 0, + "Pending default admin delay is reset"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: changeDefaultAdminDelay sets a pending default admin delay and its schedule │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule changeDefaultAdminDelay(env e, uint48 newDelay) { + require nonpayable(e); + require timeSanity(e); + require delayChangeWaitSanity(e, newDelay); + requireInvariant defaultAdminConsistency(defaultAdmin()); + requireInvariant singleDefaultAdmin(e.msg.sender, defaultAdmin()); + + uint48 delayBefore = defaultAdminDelay(e); + + changeDefaultAdminDelay@withrevert(e, newDelay); + bool success = !lastReverted; + + // liveness + assert success <=> e.msg.sender == defaultAdmin(), + "only the current default admin can begin a delay change"; + + // effect + assert success => pendingDelay_(e) == newDelay, "pending delay is set"; + assert success => ( + pendingDelaySchedule_(e) > e.block.timestamp || + delayBefore == newDelay || // Interpreted as decreasing, x - x = 0 + defaultAdminDelayIncreaseWait() == 0 + ), + "pending delay schedule is set in the future unless accepted edge cases"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: A delay can't change in less than the applied schedule │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule pendingDelayWaitEnforced(env e1, env e2, method f, calldataarg args, uint48 newDelay) { + require e1.block.timestamp < e2.block.timestamp; + + uint48 delayBefore = defaultAdminDelay(e1); + changeDefaultAdminDelay(e1, newDelay); + f(e2, args); + uint48 delayAfter = defaultAdminDelay(e2); + + mathint delayWait = newDelay > delayBefore ? increasingDelaySchedule(e1, newDelay) : decreasingDelaySchedule(e1, newDelay); + + assert delayAfter == newDelay => (e2.block.timestamp >= delayWait || delayBefore == newDelay), + "A delay can't change in less than applied schedule"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: pending delay wait is set depending on increasing or decreasing the delay │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule pendingDelayWait(env e, uint48 newDelay) { + uint48 oldDelay = defaultAdminDelay(e); + changeDefaultAdminDelay(e, newDelay); + + assert newDelay > oldDelay => pendingDelaySchedule_(e) == increasingDelaySchedule(e, newDelay), + "Delay wait is the minimum between the new delay and a threshold when the delay is increased"; + assert newDelay <= oldDelay => pendingDelaySchedule_(e) == decreasingDelaySchedule(e, newDelay), + "Delay wait is the difference between the current and the new delay when the delay is decreased"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: rollbackDefaultAdminDelay resets the delay and its schedule │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule rollbackDefaultAdminDelay(env e) { + require nonpayable(e); + requireInvariant defaultAdminConsistency(defaultAdmin()); + requireInvariant singleDefaultAdmin(e.msg.sender, defaultAdmin()); + + rollbackDefaultAdminDelay@withrevert(e); + bool success = !lastReverted; + + // liveness + assert success <=> e.msg.sender == defaultAdmin(), + "only the current default admin can rollback a delay change"; + + // effect + assert success => pendingDelay_(e) == 0, + "Pending default admin is reset"; + assert success => pendingDelaySchedule_(e) == 0, + "Pending default admin delay is reset"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: pending default admin and the delay can only change along with their corresponding schedules │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule pendingValueAndScheduleCoupling(env e, address newAdmin, uint48 newDelay) { + requireInvariant defaultAdminConsistency(defaultAdmin()); + requireInvariant singleDefaultAdmin(e.msg.sender, defaultAdmin()); + + // Pending admin + address pendingAdminBefore = pendingDefaultAdmin_(); + uint48 pendingAdminScheduleBefore = pendingDefaultAdminSchedule_(); + + beginDefaultAdminTransfer(e, newAdmin); + + address pendingAdminAfter = pendingDefaultAdmin_(); + uint48 pendingAdminScheduleAfter = pendingDefaultAdminSchedule_(); + + assert ( + pendingAdminScheduleBefore != pendingDefaultAdminSchedule_() && + pendingAdminBefore == pendingAdminAfter + ) => newAdmin == pendingAdminBefore, "pending admin stays the same if the new admin set is the same"; + + assert ( + pendingAdminBefore != pendingAdminAfter && + pendingAdminScheduleBefore == pendingDefaultAdminSchedule_() + ) => ( + // Schedule doesn't change if: + // - The defaultAdminDelay was reduced to a value such that added to the block.timestamp is equal to previous schedule + e.block.timestamp + defaultAdminDelay(e) == pendingAdminScheduleBefore + ), "pending admin stays the same if a default admin transfer is begun on accepted edge cases"; + + // Pending delay + address pendingDelayBefore = pendingDelay_(e); + uint48 pendingDelayScheduleBefore = pendingDelaySchedule_(e); + + changeDefaultAdminDelay(e, newDelay); + + address pendingDelayAfter = pendingDelay_(e); + uint48 pendingDelayScheduleAfter = pendingDelaySchedule_(e); + + assert ( + pendingDelayScheduleBefore != pendingDelayScheduleAfter && + pendingDelayBefore == pendingDelayAfter + ) => newDelay == pendingDelayBefore || pendingDelayBefore == 0, "pending delay stays the same if the new delay set is the same"; + + assert ( + pendingDelayBefore != pendingDelayAfter && + pendingDelayScheduleBefore == pendingDelayScheduleAfter + ) => ( + increasingDelaySchedule(e, newDelay) == pendingDelayScheduleBefore || + decreasingDelaySchedule(e, newDelay) == pendingDelayScheduleBefore + ), "pending delay stays the same if a default admin transfer is begun on accepted edge cases"; +} diff --git a/certora/specs/methods/IAccessControlDefaultAdminRules.spec b/certora/specs/methods/IAccessControlDefaultAdminRules.spec new file mode 100644 index 000000000..a9dd08b7f --- /dev/null +++ b/certora/specs/methods/IAccessControlDefaultAdminRules.spec @@ -0,0 +1,36 @@ +import "./IERC5313.spec" + +methods { + // === View == + + // Default Admin + defaultAdmin() returns(address) envfree + pendingDefaultAdmin() returns(address, uint48) envfree + + // Default Admin Delay + defaultAdminDelay() returns(uint48) + pendingDefaultAdminDelay() returns(uint48, uint48) + defaultAdminDelayIncreaseWait() returns(uint48) envfree + + // === Mutations == + + // Default Admin + beginDefaultAdminTransfer(address) + cancelDefaultAdminTransfer() + acceptDefaultAdminTransfer() + + // Default Admin Delay + changeDefaultAdminDelay(uint48) + rollbackDefaultAdminDelay() + + // == FV == + + // Default Admin + pendingDefaultAdmin_() returns (address) envfree + pendingDefaultAdminSchedule_() returns (uint48) envfree + + // Default Admin Delay + pendingDelay_() returns (uint48) + pendingDelaySchedule_() returns (uint48) + delayChangeWait_(uint48) returns (uint48) +} diff --git a/certora/specs/methods/IERC5313.spec b/certora/specs/methods/IERC5313.spec new file mode 100644 index 000000000..d4c5a0412 --- /dev/null +++ b/certora/specs/methods/IERC5313.spec @@ -0,0 +1,3 @@ +methods { + owner() returns (address) envfree +} From 72ed4ca67a99bba17852fb6a7dea558980260757 Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Fri, 5 May 2023 21:31:23 +0200 Subject: [PATCH 117/133] Ensure AccessControlDefaultAdminRules's initialDefaultAdmin is non-zero (#4220) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ernesto García --- contracts/access/AccessControlDefaultAdminRules.sol | 1 + test/access/AccessControlDefaultAdminRules.test.js | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/contracts/access/AccessControlDefaultAdminRules.sol b/contracts/access/AccessControlDefaultAdminRules.sol index 0c640fb99..6cdda81a1 100644 --- a/contracts/access/AccessControlDefaultAdminRules.sol +++ b/contracts/access/AccessControlDefaultAdminRules.sol @@ -53,6 +53,7 @@ abstract contract AccessControlDefaultAdminRules is IAccessControlDefaultAdminRu * @dev Sets the initial values for {defaultAdminDelay} and {defaultAdmin} address. */ constructor(uint48 initialDelay, address initialDefaultAdmin) { + require(initialDefaultAdmin != address(0), "AccessControl: 0 default admin"); _currentDelay = initialDelay; _grantRole(DEFAULT_ADMIN_ROLE, initialDefaultAdmin); } diff --git a/test/access/AccessControlDefaultAdminRules.test.js b/test/access/AccessControlDefaultAdminRules.test.js index 4e3167a46..be112481e 100644 --- a/test/access/AccessControlDefaultAdminRules.test.js +++ b/test/access/AccessControlDefaultAdminRules.test.js @@ -1,4 +1,4 @@ -const { time } = require('@openzeppelin/test-helpers'); +const { time, constants, expectRevert } = require('@openzeppelin/test-helpers'); const { shouldBehaveLikeAccessControl, shouldBehaveLikeAccessControlDefaultAdminRules, @@ -13,6 +13,13 @@ contract('AccessControlDefaultAdminRules', function (accounts) { this.accessControl = await AccessControlDefaultAdminRules.new(delay, accounts[0], { from: accounts[0] }); }); + it('initial admin not zero', async function () { + await expectRevert( + AccessControlDefaultAdminRules.new(delay, constants.ZERO_ADDRESS), + 'AccessControl: 0 default admin', + ); + }); + shouldBehaveLikeAccessControl('AccessControl', ...accounts); shouldBehaveLikeAccessControlDefaultAdminRules('AccessControl', delay, ...accounts); }); From 692d8c85a494f78b83aa4de44dcce4e3e63997d1 Mon Sep 17 00:00:00 2001 From: ToonVanHove Date: Fri, 5 May 2023 22:25:23 +0200 Subject: [PATCH 118/133] Fix lookup documentation in ERC20Votes and Checkpoints (#4218) Co-authored-by: Hadrien Croubois --- .../token/ERC20/extensions/ERC20Votes.sol | 2 +- contracts/utils/Checkpoints.sol | 24 +++++++++---------- scripts/generate/templates/Checkpoints.js | 10 ++++---- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/contracts/token/ERC20/extensions/ERC20Votes.sol b/contracts/token/ERC20/extensions/ERC20Votes.sol index d72d34f81..f44b89604 100644 --- a/contracts/token/ERC20/extensions/ERC20Votes.sol +++ b/contracts/token/ERC20/extensions/ERC20Votes.sol @@ -114,7 +114,7 @@ abstract contract ERC20Votes is ERC20Permit, IERC5805 { * @dev Lookup a value in a list of (sorted) checkpoints. */ function _checkpointsLookup(Checkpoint[] storage ckpts, uint256 timepoint) private view returns (uint256) { - // We run a binary search to look for the earliest checkpoint taken after `timepoint`. + // We run a binary search to look for the last (most recent) checkpoint taken before (or at) `timepoint`. // // Initially we check if the block is recent to narrow the search range. // During the loop, the index of the wanted checkpoint remains in the range [low-1, high). diff --git a/contracts/utils/Checkpoints.sol b/contracts/utils/Checkpoints.sol index 7d7905fd1..27da4b517 100644 --- a/contracts/utils/Checkpoints.sol +++ b/contracts/utils/Checkpoints.sol @@ -151,7 +151,7 @@ library Checkpoints { } /** - * @dev Return the index of the oldest checkpoint whose key is greater than the search key, or `high` if there is none. + * @dev Return the index of the last (most recent) checkpoint with key lower or equal than the search key, or `high` if there is none. * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`. * * WARNING: `high` should not be greater than the array's length. @@ -174,7 +174,7 @@ library Checkpoints { } /** - * @dev Return the index of the oldest checkpoint whose key is greater or equal than the search key, or `high` if there is none. + * @dev Return the index of the first (oldest) checkpoint with key is greater or equal than the search key, or `high` if there is none. * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`. * * WARNING: `high` should not be greater than the array's length. @@ -225,7 +225,7 @@ library Checkpoints { } /** - * @dev Returns the value in the oldest checkpoint with key greater or equal than the search key, or zero if there is none. + * @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if there is none. */ function lowerLookup(Trace224 storage self, uint32 key) internal view returns (uint224) { uint256 len = self._checkpoints.length; @@ -234,7 +234,7 @@ library Checkpoints { } /** - * @dev Returns the value in the most recent checkpoint with key lower or equal than the search key. + * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key. */ function upperLookup(Trace224 storage self, uint32 key) internal view returns (uint224) { uint256 len = self._checkpoints.length; @@ -243,7 +243,7 @@ library Checkpoints { } /** - * @dev Returns the value in the most recent checkpoint with key lower or equal than the search key. + * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key. * * NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high keys). */ @@ -324,7 +324,7 @@ library Checkpoints { } /** - * @dev Return the index of the oldest checkpoint whose key is greater than the search key, or `high` if there is none. + * @dev Return the index of the last (most recent) checkpoint with key lower or equal than the search key, or `high` if there is none. * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`. * * WARNING: `high` should not be greater than the array's length. @@ -347,7 +347,7 @@ library Checkpoints { } /** - * @dev Return the index of the oldest checkpoint whose key is greater or equal than the search key, or `high` if there is none. + * @dev Return the index of the first (oldest) checkpoint with key is greater or equal than the search key, or `high` if there is none. * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`. * * WARNING: `high` should not be greater than the array's length. @@ -401,7 +401,7 @@ library Checkpoints { } /** - * @dev Returns the value in the oldest checkpoint with key greater or equal than the search key, or zero if there is none. + * @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if there is none. */ function lowerLookup(Trace160 storage self, uint96 key) internal view returns (uint160) { uint256 len = self._checkpoints.length; @@ -410,7 +410,7 @@ library Checkpoints { } /** - * @dev Returns the value in the most recent checkpoint with key lower or equal than the search key. + * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key. */ function upperLookup(Trace160 storage self, uint96 key) internal view returns (uint160) { uint256 len = self._checkpoints.length; @@ -419,7 +419,7 @@ library Checkpoints { } /** - * @dev Returns the value in the most recent checkpoint with key lower or equal than the search key. + * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key. * * NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high keys). */ @@ -500,7 +500,7 @@ library Checkpoints { } /** - * @dev Return the index of the oldest checkpoint whose key is greater than the search key, or `high` if there is none. + * @dev Return the index of the last (most recent) checkpoint with key lower or equal than the search key, or `high` if there is none. * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`. * * WARNING: `high` should not be greater than the array's length. @@ -523,7 +523,7 @@ library Checkpoints { } /** - * @dev Return the index of the oldest checkpoint whose key is greater or equal than the search key, or `high` if there is none. + * @dev Return the index of the first (oldest) checkpoint with key is greater or equal than the search key, or `high` if there is none. * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`. * * WARNING: `high` should not be greater than the array's length. diff --git a/scripts/generate/templates/Checkpoints.js b/scripts/generate/templates/Checkpoints.js index 18999682d..1d79031da 100644 --- a/scripts/generate/templates/Checkpoints.js +++ b/scripts/generate/templates/Checkpoints.js @@ -46,7 +46,7 @@ function push( } /** - * @dev Returns the value in the oldest checkpoint with key greater or equal than the search key, or zero if there is none. + * @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if there is none. */ function lowerLookup(${opts.historyTypeName} storage self, ${opts.keyTypeName} key) internal view returns (${opts.valueTypeName}) { uint256 len = self.${opts.checkpointFieldName}.length; @@ -55,7 +55,7 @@ function lowerLookup(${opts.historyTypeName} storage self, ${opts.keyTypeName} k } /** - * @dev Returns the value in the most recent checkpoint with key lower or equal than the search key. + * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key. */ function upperLookup(${opts.historyTypeName} storage self, ${opts.keyTypeName} key) internal view returns (${opts.valueTypeName}) { uint256 len = self.${opts.checkpointFieldName}.length; @@ -64,7 +64,7 @@ function upperLookup(${opts.historyTypeName} storage self, ${opts.keyTypeName} k } /** - * @dev Returns the value in the most recent checkpoint with key lower or equal than the search key. + * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key. * * NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high keys). */ @@ -227,7 +227,7 @@ function _insert( } /** - * @dev Return the index of the oldest checkpoint whose key is greater than the search key, or \`high\` if there is none. + * @dev Return the index of the last (most recent) checkpoint with key lower or equal than the search key, or \`high\` if there is none. * \`low\` and \`high\` define a section where to do the search, with inclusive \`low\` and exclusive \`high\`. * * WARNING: \`high\` should not be greater than the array's length. @@ -250,7 +250,7 @@ function _upperBinaryLookup( } /** - * @dev Return the index of the oldest checkpoint whose key is greater or equal than the search key, or \`high\` if there is none. + * @dev Return the index of the first (oldest) checkpoint with key is greater or equal than the search key, or \`high\` if there is none. * \`low\` and \`high\` define a section where to do the search, with inclusive \`low\` and exclusive \`high\`. * * WARNING: \`high\` should not be greater than the array's length. From 908f78d07b7b28c79af04bf0fc90501a81246b0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Garc=C3=ADa?= Date: Mon, 8 May 2023 23:00:49 +0200 Subject: [PATCH 119/133] Enable more Slither detectors (#4219) --- package.json | 2 +- slither.config.json | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 56798f788..a3b98fe37 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "test:inheritance": "scripts/checks/inheritance-ordering.js artifacts/build-info/*", "test:generation": "scripts/checks/generation.sh", "gas-report": "env ENABLE_GAS_REPORT=true npm run test", - "slither": "npm run clean && slither . --detect reentrancy-eth,reentrancy-no-eth,reentrancy-unlimited-gas" + "slither": "npm run clean && slither ." }, "repository": { "type": "git", diff --git a/slither.config.json b/slither.config.json index 2b618794a..069da1f3a 100644 --- a/slither.config.json +++ b/slither.config.json @@ -1,5 +1,5 @@ { - "detectors_to_run": "reentrancy-eth,reentrancy-no-eth,reentrancy-unlimited-gas", - "filter_paths": "contracts/mocks", + "detectors_to_run": "arbitrary-send-erc20,array-by-reference,incorrect-shift,name-reused,rtlo,suicidal,uninitialized-state,uninitialized-storage,arbitrary-send-erc20-permit,controlled-array-length,controlled-delegatecall,delegatecall-loop,msg-value-loop,reentrancy-eth,unchecked-transfer,weak-prng,domain-separator-collision,erc20-interface,erc721-interface,locked-ether,mapping-deletion,shadowing-abstract,tautology,write-after-write,boolean-cst,reentrancy-no-eth,reused-constructor,tx-origin,unchecked-lowlevel,unchecked-send,variable-scope,void-cst,events-access,events-maths,incorrect-unary,boolean-equal,cyclomatic-complexity,deprecated-standards,erc20-indexed,function-init-state,pragma,unused-state,reentrancy-unlimited-gas,constable-states,immutable-states,var-read-using-this", + "filter_paths": "contracts/mocks,contracts-exposed", "compile_force_framework": "hardhat" -} \ No newline at end of file +} From 832c352c7d68c75a89974bd1e4623bd1a1618ab0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 9 May 2023 00:04:41 -0300 Subject: [PATCH 120/133] Update lockfile (#4203) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package-lock.json | 3346 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 2547 insertions(+), 799 deletions(-) diff --git a/package-lock.json b/package-lock.json index f44a1b939..2219b08f2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -53,9 +53,9 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", + "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", "dev": true, "dependencies": { "@babel/highlight": "^7.18.6" @@ -88,9 +88,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", - "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.5.tgz", + "integrity": "sha512-8jI69toZqqcsnqGGqwGS4Qb1VwLOEp4hz+CXPywcvjs60u3B4Pom/U/7rm4W8tMOYEB+E9wgD0mW1l3r8qlI9Q==", "dev": true, "dependencies": { "regenerator-runtime": "^0.13.11" @@ -99,6 +99,32 @@ "node": ">=6.9.0" } }, + "node_modules/@chainsafe/as-sha256": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@chainsafe/as-sha256/-/as-sha256-0.3.1.tgz", + "integrity": "sha512-hldFFYuf49ed7DAakWVXSJODuq3pzJEguD8tQ7h+sGkM18vja+OFoJI9krnGmgzyuZC2ETX0NOIcCTy31v2Mtg==", + "dev": true + }, + "node_modules/@chainsafe/persistent-merkle-tree": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.4.2.tgz", + "integrity": "sha512-lLO3ihKPngXLTus/L7WHKaw9PnNJWizlOF1H9NNzHP6Xvh82vzg9F2bzkXhYIFshMZ2gTCEz8tq6STe7r5NDfQ==", + "dev": true, + "dependencies": { + "@chainsafe/as-sha256": "^0.3.1" + } + }, + "node_modules/@chainsafe/ssz": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.9.4.tgz", + "integrity": "sha512-77Qtg2N1ayqs4Bg/wvnWfg5Bta7iy7IRh8XqXh7oNMeP2HBbBwx8m6yTpA8p0EHItWPEBkgZd5S5/LSlp3GXuQ==", + "dev": true, + "dependencies": { + "@chainsafe/as-sha256": "^0.3.1", + "@chainsafe/persistent-merkle-tree": "^0.4.2", + "case": "^1.6.3" + } + }, "node_modules/@changesets/apply-release-plan": { "version": "6.1.3", "resolved": "https://registry.npmjs.org/@changesets/apply-release-plan/-/apply-release-plan-6.1.3.tgz", @@ -173,9 +199,9 @@ } }, "node_modules/@changesets/cli": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/@changesets/cli/-/cli-2.26.0.tgz", - "integrity": "sha512-0cbTiDms+ICTVtEwAFLNW0jBNex9f5+fFv3I771nBvdnV/mOjd1QJ4+f8KtVSOrwD9SJkk9xbDkWFb0oXd8d1Q==", + "version": "2.26.1", + "resolved": "https://registry.npmjs.org/@changesets/cli/-/cli-2.26.1.tgz", + "integrity": "sha512-XnTa+b51vt057fyAudvDKGB0Sh72xutQZNAdXkCqPBKO2zvs2yYZx5hFZj1u9cbtpwM6Sxtcr02/FQJfZOzemQ==", "dev": true, "dependencies": { "@babel/runtime": "^7.20.1", @@ -500,9 +526,9 @@ "dev": true }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.2.0.tgz", - "integrity": "sha512-gB8T4H4DEfX2IV9zGDJPOBgP1e/DbfCPDTtEqUMckpvzS1OYtva8JdFYBqMwYk7xAQ429WGF/UPqn8uQ//h2vQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", "dev": true, "dependencies": { "eslint-visitor-keys": "^3.3.0" @@ -515,23 +541,23 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.4.0.tgz", - "integrity": "sha512-A9983Q0LnDGdLPjxyXQ00sbV+K+O+ko2Dr+CZigbHWtX9pNfxlaBkMR8X1CztI73zuEyEBXTVjx7CE+/VSwDiQ==", + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", + "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.1.tgz", - "integrity": "sha512-eFRmABvW2E5Ho6f5fHLqgena46rOj7r7OKHYfLElqcBfGFHHpjBhivyi5+jOEQuSpdc/1phIZJlbC2te+tZNIw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", + "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.5.0", + "espree": "^9.5.1", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -565,9 +591,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.36.0.tgz", - "integrity": "sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.39.0.tgz", + "integrity": "sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1536,34 +1562,84 @@ } }, "node_modules/@nomicfoundation/ethereumjs-block": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-4.0.0.tgz", - "integrity": "sha512-bk8uP8VuexLgyIZAHExH1QEovqx0Lzhc9Ntm63nCRKLHXIZkobaFaeCVwTESV7YkPKUk7NiK11s8ryed4CS9yA==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-5.0.1.tgz", + "integrity": "sha512-u1Yioemi6Ckj3xspygu/SfFvm8vZEO8/Yx5a1QLzi6nVU0jz3Pg2OmHKJ5w+D9Ogk1vhwRiqEBAqcb0GVhCyHw==", "dev": true, "dependencies": { - "@nomicfoundation/ethereumjs-common": "^3.0.0", - "@nomicfoundation/ethereumjs-rlp": "^4.0.0", - "@nomicfoundation/ethereumjs-trie": "^5.0.0", - "@nomicfoundation/ethereumjs-tx": "^4.0.0", - "@nomicfoundation/ethereumjs-util": "^8.0.0", - "ethereum-cryptography": "0.1.3" + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-trie": "6.0.1", + "@nomicfoundation/ethereumjs-tx": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "ethereum-cryptography": "0.1.3", + "ethers": "^5.7.1" }, "engines": { "node": ">=14" } }, + "node_modules/@nomicfoundation/ethereumjs-block/node_modules/ethers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz", + "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abi": "5.7.0", + "@ethersproject/abstract-provider": "5.7.0", + "@ethersproject/abstract-signer": "5.7.0", + "@ethersproject/address": "5.7.0", + "@ethersproject/base64": "5.7.0", + "@ethersproject/basex": "5.7.0", + "@ethersproject/bignumber": "5.7.0", + "@ethersproject/bytes": "5.7.0", + "@ethersproject/constants": "5.7.0", + "@ethersproject/contracts": "5.7.0", + "@ethersproject/hash": "5.7.0", + "@ethersproject/hdnode": "5.7.0", + "@ethersproject/json-wallets": "5.7.0", + "@ethersproject/keccak256": "5.7.0", + "@ethersproject/logger": "5.7.0", + "@ethersproject/networks": "5.7.1", + "@ethersproject/pbkdf2": "5.7.0", + "@ethersproject/properties": "5.7.0", + "@ethersproject/providers": "5.7.2", + "@ethersproject/random": "5.7.0", + "@ethersproject/rlp": "5.7.0", + "@ethersproject/sha2": "5.7.0", + "@ethersproject/signing-key": "5.7.0", + "@ethersproject/solidity": "5.7.0", + "@ethersproject/strings": "5.7.0", + "@ethersproject/transactions": "5.7.0", + "@ethersproject/units": "5.7.0", + "@ethersproject/wallet": "5.7.0", + "@ethersproject/web": "5.7.1", + "@ethersproject/wordlists": "5.7.0" + } + }, "node_modules/@nomicfoundation/ethereumjs-blockchain": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-blockchain/-/ethereumjs-blockchain-6.0.0.tgz", - "integrity": "sha512-pLFEoea6MWd81QQYSReLlLfH7N9v7lH66JC/NMPN848ySPPQA5renWnE7wPByfQFzNrPBuDDRFFULMDmj1C0xw==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-blockchain/-/ethereumjs-blockchain-7.0.1.tgz", + "integrity": "sha512-NhzndlGg829XXbqJEYrF1VeZhAwSPgsK/OB7TVrdzft3y918hW5KNd7gIZ85sn6peDZOdjBsAXIpXZ38oBYE5A==", "dev": true, "dependencies": { - "@nomicfoundation/ethereumjs-block": "^4.0.0", - "@nomicfoundation/ethereumjs-common": "^3.0.0", - "@nomicfoundation/ethereumjs-ethash": "^2.0.0", - "@nomicfoundation/ethereumjs-rlp": "^4.0.0", - "@nomicfoundation/ethereumjs-trie": "^5.0.0", - "@nomicfoundation/ethereumjs-util": "^8.0.0", + "@nomicfoundation/ethereumjs-block": "5.0.1", + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-ethash": "3.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-trie": "6.0.1", + "@nomicfoundation/ethereumjs-tx": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", "abstract-level": "^1.0.3", "debug": "^4.3.3", "ethereum-cryptography": "0.1.3", @@ -1576,24 +1652,24 @@ } }, "node_modules/@nomicfoundation/ethereumjs-common": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-3.0.0.tgz", - "integrity": "sha512-WS7qSshQfxoZOpHG/XqlHEGRG1zmyjYrvmATvc4c62+gZXgre1ymYP8ZNgx/3FyZY0TWe9OjFlKOfLqmgOeYwA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.1.tgz", + "integrity": "sha512-OBErlkfp54GpeiE06brBW/TTbtbuBJV5YI5Nz/aB2evTDo+KawyEzPjBlSr84z/8MFfj8wS2wxzQX1o32cev5g==", "dev": true, "dependencies": { - "@nomicfoundation/ethereumjs-util": "^8.0.0", + "@nomicfoundation/ethereumjs-util": "9.0.1", "crc-32": "^1.2.0" } }, "node_modules/@nomicfoundation/ethereumjs-ethash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-ethash/-/ethereumjs-ethash-2.0.0.tgz", - "integrity": "sha512-WpDvnRncfDUuXdsAXlI4lXbqUDOA+adYRQaEezIkxqDkc+LDyYDbd/xairmY98GnQzo1zIqsIL6GB5MoMSJDew==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-ethash/-/ethereumjs-ethash-3.0.1.tgz", + "integrity": "sha512-KDjGIB5igzWOp8Ik5I6QiRH5DH+XgILlplsHR7TEuWANZA759G6krQ6o8bvj+tRUz08YygMQu/sGd9mJ1DYT8w==", "dev": true, "dependencies": { - "@nomicfoundation/ethereumjs-block": "^4.0.0", - "@nomicfoundation/ethereumjs-rlp": "^4.0.0", - "@nomicfoundation/ethereumjs-util": "^8.0.0", + "@nomicfoundation/ethereumjs-block": "5.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", "abstract-level": "^1.0.3", "bigint-crypto-utils": "^3.0.23", "ethereum-cryptography": "0.1.3" @@ -1603,15 +1679,15 @@ } }, "node_modules/@nomicfoundation/ethereumjs-evm": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-evm/-/ethereumjs-evm-1.0.0.tgz", - "integrity": "sha512-hVS6qRo3V1PLKCO210UfcEQHvlG7GqR8iFzp0yyjTg2TmJQizcChKgWo8KFsdMw6AyoLgLhHGHw4HdlP8a4i+Q==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-evm/-/ethereumjs-evm-2.0.1.tgz", + "integrity": "sha512-oL8vJcnk0Bx/onl+TgQOQ1t/534GKFaEG17fZmwtPFeH8S5soiBYPCLUrvANOl4sCp9elYxIMzIiTtMtNNN8EQ==", "dev": true, "dependencies": { - "@nomicfoundation/ethereumjs-common": "^3.0.0", - "@nomicfoundation/ethereumjs-util": "^8.0.0", - "@types/async-eventemitter": "^0.2.1", - "async-eventemitter": "^0.2.4", + "@ethersproject/providers": "^5.7.1", + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-tx": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", "debug": "^4.3.3", "ethereum-cryptography": "0.1.3", "mcl-wasm": "^0.7.1", @@ -1622,9 +1698,9 @@ } }, "node_modules/@nomicfoundation/ethereumjs-rlp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-4.0.0.tgz", - "integrity": "sha512-GaSOGk5QbUk4eBP5qFbpXoZoZUj/NrW7MRa0tKY4Ew4c2HAS0GXArEMAamtFrkazp0BO4K5p2ZCG3b2FmbShmw==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.1.tgz", + "integrity": "sha512-xtxrMGa8kP4zF5ApBQBtjlSbN5E2HI8m8FYgVSYAnO6ssUoY5pVPGy2H8+xdf/bmMa22Ce8nWMH3aEW8CcqMeQ==", "dev": true, "bin": { "rlp": "bin/rlp" @@ -1634,28 +1710,76 @@ } }, "node_modules/@nomicfoundation/ethereumjs-statemanager": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-statemanager/-/ethereumjs-statemanager-1.0.0.tgz", - "integrity": "sha512-jCtqFjcd2QejtuAMjQzbil/4NHf5aAWxUc+CvS0JclQpl+7M0bxMofR2AJdtz+P3u0ke2euhYREDiE7iSO31vQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-statemanager/-/ethereumjs-statemanager-2.0.1.tgz", + "integrity": "sha512-B5ApMOnlruVOR7gisBaYwFX+L/AP7i/2oAahatssjPIBVDF6wTX1K7Qpa39E/nzsH8iYuL3krkYeUFIdO3EMUQ==", "dev": true, "dependencies": { - "@nomicfoundation/ethereumjs-common": "^3.0.0", - "@nomicfoundation/ethereumjs-rlp": "^4.0.0", - "@nomicfoundation/ethereumjs-trie": "^5.0.0", - "@nomicfoundation/ethereumjs-util": "^8.0.0", + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", "debug": "^4.3.3", "ethereum-cryptography": "0.1.3", - "functional-red-black-tree": "^1.0.1" + "ethers": "^5.7.1", + "js-sdsl": "^4.1.4" + } + }, + "node_modules/@nomicfoundation/ethereumjs-statemanager/node_modules/ethers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz", + "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abi": "5.7.0", + "@ethersproject/abstract-provider": "5.7.0", + "@ethersproject/abstract-signer": "5.7.0", + "@ethersproject/address": "5.7.0", + "@ethersproject/base64": "5.7.0", + "@ethersproject/basex": "5.7.0", + "@ethersproject/bignumber": "5.7.0", + "@ethersproject/bytes": "5.7.0", + "@ethersproject/constants": "5.7.0", + "@ethersproject/contracts": "5.7.0", + "@ethersproject/hash": "5.7.0", + "@ethersproject/hdnode": "5.7.0", + "@ethersproject/json-wallets": "5.7.0", + "@ethersproject/keccak256": "5.7.0", + "@ethersproject/logger": "5.7.0", + "@ethersproject/networks": "5.7.1", + "@ethersproject/pbkdf2": "5.7.0", + "@ethersproject/properties": "5.7.0", + "@ethersproject/providers": "5.7.2", + "@ethersproject/random": "5.7.0", + "@ethersproject/rlp": "5.7.0", + "@ethersproject/sha2": "5.7.0", + "@ethersproject/signing-key": "5.7.0", + "@ethersproject/solidity": "5.7.0", + "@ethersproject/strings": "5.7.0", + "@ethersproject/transactions": "5.7.0", + "@ethersproject/units": "5.7.0", + "@ethersproject/wallet": "5.7.0", + "@ethersproject/web": "5.7.1", + "@ethersproject/wordlists": "5.7.0" } }, "node_modules/@nomicfoundation/ethereumjs-trie": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-trie/-/ethereumjs-trie-5.0.0.tgz", - "integrity": "sha512-LIj5XdE+s+t6WSuq/ttegJzZ1vliwg6wlb+Y9f4RlBpuK35B9K02bO7xU+E6Rgg9RGptkWd6TVLdedTI4eNc2A==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-trie/-/ethereumjs-trie-6.0.1.tgz", + "integrity": "sha512-A64It/IMpDVODzCgxDgAAla8jNjNtsoQZIzZUfIV5AY6Coi4nvn7+VReBn5itlxMiL2yaTlQr9TRWp3CSI6VoA==", "dev": true, "dependencies": { - "@nomicfoundation/ethereumjs-rlp": "^4.0.0", - "@nomicfoundation/ethereumjs-util": "^8.0.0", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "@types/readable-stream": "^2.3.13", "ethereum-cryptography": "0.1.3", "readable-stream": "^3.6.0" }, @@ -1664,14 +1788,16 @@ } }, "node_modules/@nomicfoundation/ethereumjs-tx": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-4.0.0.tgz", - "integrity": "sha512-Gg3Lir2lNUck43Kp/3x6TfBNwcWC9Z1wYue9Nz3v4xjdcv6oDW9QSMJxqsKw9QEGoBBZ+gqwpW7+F05/rs/g1w==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.1.tgz", + "integrity": "sha512-0HwxUF2u2hrsIM1fsasjXvlbDOq1ZHFV2dd1yGq8CA+MEYhaxZr8OTScpVkkxqMwBcc5y83FyPl0J9MZn3kY0w==", "dev": true, "dependencies": { - "@nomicfoundation/ethereumjs-common": "^3.0.0", - "@nomicfoundation/ethereumjs-rlp": "^4.0.0", - "@nomicfoundation/ethereumjs-util": "^8.0.0", + "@chainsafe/ssz": "^0.9.2", + "@ethersproject/providers": "^5.7.2", + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", "ethereum-cryptography": "0.1.3" }, "engines": { @@ -1679,38 +1805,55 @@ } }, "node_modules/@nomicfoundation/ethereumjs-util": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-8.0.0.tgz", - "integrity": "sha512-2emi0NJ/HmTG+CGY58fa+DQuAoroFeSH9gKu9O6JnwTtlzJtgfTixuoOqLEgyyzZVvwfIpRueuePb8TonL1y+A==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.1.tgz", + "integrity": "sha512-TwbhOWQ8QoSCFhV/DDfSmyfFIHjPjFBj957219+V3jTZYZ2rf9PmDtNOeZWAE3p3vlp8xb02XGpd0v6nTUPbsA==", "dev": true, "dependencies": { - "@nomicfoundation/ethereumjs-rlp": "^4.0.0-beta.2", + "@chainsafe/ssz": "^0.10.0", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", "ethereum-cryptography": "0.1.3" }, "engines": { "node": ">=14" } }, - "node_modules/@nomicfoundation/ethereumjs-vm": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-vm/-/ethereumjs-vm-6.0.0.tgz", - "integrity": "sha512-JMPxvPQ3fzD063Sg3Tp+UdwUkVxMoo1uML6KSzFhMH3hoQi/LMuXBoEHAoW83/vyNS9BxEe6jm6LmT5xdeEJ6w==", + "node_modules/@nomicfoundation/ethereumjs-util/node_modules/@chainsafe/persistent-merkle-tree": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.5.0.tgz", + "integrity": "sha512-l0V1b5clxA3iwQLXP40zYjyZYospQLZXzBVIhhr9kDg/1qHZfzzHw0jj4VPBijfYCArZDlPkRi1wZaV2POKeuw==", "dev": true, "dependencies": { - "@nomicfoundation/ethereumjs-block": "^4.0.0", - "@nomicfoundation/ethereumjs-blockchain": "^6.0.0", - "@nomicfoundation/ethereumjs-common": "^3.0.0", - "@nomicfoundation/ethereumjs-evm": "^1.0.0", - "@nomicfoundation/ethereumjs-rlp": "^4.0.0", - "@nomicfoundation/ethereumjs-statemanager": "^1.0.0", - "@nomicfoundation/ethereumjs-trie": "^5.0.0", - "@nomicfoundation/ethereumjs-tx": "^4.0.0", - "@nomicfoundation/ethereumjs-util": "^8.0.0", - "@types/async-eventemitter": "^0.2.1", - "async-eventemitter": "^0.2.4", + "@chainsafe/as-sha256": "^0.3.1" + } + }, + "node_modules/@nomicfoundation/ethereumjs-util/node_modules/@chainsafe/ssz": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.10.2.tgz", + "integrity": "sha512-/NL3Lh8K+0q7A3LsiFq09YXS9fPE+ead2rr7vM2QK8PLzrNsw3uqrif9bpRX5UxgeRjM+vYi+boCM3+GM4ovXg==", + "dev": true, + "dependencies": { + "@chainsafe/as-sha256": "^0.3.1", + "@chainsafe/persistent-merkle-tree": "^0.5.0" + } + }, + "node_modules/@nomicfoundation/ethereumjs-vm": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-vm/-/ethereumjs-vm-7.0.1.tgz", + "integrity": "sha512-rArhyn0jPsS/D+ApFsz3yVJMQ29+pVzNZ0VJgkzAZ+7FqXSRtThl1C1prhmlVr3YNUlfpZ69Ak+RUT4g7VoOuQ==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-block": "5.0.1", + "@nomicfoundation/ethereumjs-blockchain": "7.0.1", + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-evm": "2.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-statemanager": "2.0.1", + "@nomicfoundation/ethereumjs-trie": "6.0.1", + "@nomicfoundation/ethereumjs-tx": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", "debug": "^4.3.3", "ethereum-cryptography": "0.1.3", - "functional-red-black-tree": "^1.0.1", "mcl-wasm": "^0.7.1", "rustbn.js": "~0.2.0" }, @@ -2115,9 +2258,9 @@ } }, "node_modules/@openzeppelin/upgrades-core": { - "version": "1.24.1", - "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades-core/-/upgrades-core-1.24.1.tgz", - "integrity": "sha512-QhdIQDUykJ3vQauB6CheV7vk4zgn0e1iY+IDg7r1KqpA1m2bqIGjQCpzidW33K4bZc9zdJSPx2/Z6Um5KxCB7A==", + "version": "1.25.0", + "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades-core/-/upgrades-core-1.25.0.tgz", + "integrity": "sha512-vSxOSm1k+P156nNm15ydhOmSPGC37mnl092FMVOH+eGaoqLjr2Za6ULVjDMFzvMnG+sGE1UoDOqBNPfTm0ch8w==", "dev": true, "dependencies": { "cbor": "^8.0.0", @@ -2390,16 +2533,40 @@ "web3-utils": "1.8.2" } }, + "node_modules/@truffle/abi-utils/node_modules/bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "dev": true + }, + "node_modules/@truffle/abi-utils/node_modules/web3-utils": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.8.2.tgz", + "integrity": "sha512-v7j6xhfLQfY7xQDrUP0BKbaNrmZ2/+egbqP9q3KYmOiPpnvAfol+32slgL0WX/5n8VPvKCK5EZ1HGrAVICSToA==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereumjs-util": "^7.1.0", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/@truffle/blockchain-utils": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@truffle/blockchain-utils/-/blockchain-utils-0.1.6.tgz", - "integrity": "sha512-SldoNRIFSm3+HMBnSc2jFsu5TWDkCN4X6vL3wrd0t6DIeF7nD6EoPPjxwbFSoqCnkkRxMuZeL6sUx7UMJS/wSA==", + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/@truffle/blockchain-utils/-/blockchain-utils-0.1.7.tgz", + "integrity": "sha512-1nibqGjEHC7KAyDThEFvbm2+EO8zAHee/VjCtxkYBE3ySwP50joh0QCEBjy7K/9z+icpMoDucfxmgaKToBFUgQ==", "dev": true }, "node_modules/@truffle/codec": { - "version": "0.14.16", - "resolved": "https://registry.npmjs.org/@truffle/codec/-/codec-0.14.16.tgz", - "integrity": "sha512-a9UY3n/FnkKN3Q4zOuMFOOcLWb80mdknj+voim4vvXYtJm1aAZQZE5sG9aLnMBTl4TiGLzUtfNDVYY7WgWgDag==", + "version": "0.14.17", + "resolved": "https://registry.npmjs.org/@truffle/codec/-/codec-0.14.17.tgz", + "integrity": "sha512-kD4dD86huLeaBEq5R8D1zleJEu6NsXbyYLdXl1V1TKdiO8odw5CBC6Y/+wdu5d3t1dyEYrTbhn1dqknZa52pmw==", "dev": true, "dependencies": { "@truffle/abi-utils": "^0.3.9", @@ -2478,6 +2645,24 @@ "node": ">=10" } }, + "node_modules/@truffle/codec/node_modules/web3-utils": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.8.2.tgz", + "integrity": "sha512-v7j6xhfLQfY7xQDrUP0BKbaNrmZ2/+egbqP9q3KYmOiPpnvAfol+32slgL0WX/5n8VPvKCK5EZ1HGrAVICSToA==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereumjs-util": "^7.1.0", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/@truffle/codec/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -2501,17 +2686,17 @@ "dev": true }, "node_modules/@truffle/contract": { - "version": "4.6.17", - "resolved": "https://registry.npmjs.org/@truffle/contract/-/contract-4.6.17.tgz", - "integrity": "sha512-sIMam5Wqr9AEiqHfOcWGJGqTv8Qy+BT765PaNHUUT6JBAY+tpHM3FlQd2nM6zLJ8paR3SLDGIthkhCBH/KNgDA==", + "version": "4.6.20", + "resolved": "https://registry.npmjs.org/@truffle/contract/-/contract-4.6.20.tgz", + "integrity": "sha512-s7Mbc37L/CF5Apy/cjPnalkgACmG9tTAmcIW28cIZLRLOUAze18pqhtdHryxAQhEOtKGaDAho6TriqL7/74uHw==", "dev": true, "dependencies": { "@ensdomains/ensjs": "^2.1.0", - "@truffle/blockchain-utils": "^0.1.6", + "@truffle/blockchain-utils": "^0.1.7", "@truffle/contract-schema": "^3.4.13", - "@truffle/debug-utils": "^6.0.47", + "@truffle/debug-utils": "^6.0.48", "@truffle/error": "^0.2.0", - "@truffle/interface-adapter": "^0.5.30", + "@truffle/interface-adapter": "^0.5.32", "bignumber.js": "^7.2.1", "debug": "^4.3.1", "ethers": "^4.0.32", @@ -2538,13 +2723,391 @@ "integrity": "sha512-Fe0/z4WWb7IP2gBnv3l6zqP87Y0kSMs7oiSLakKJq17q3GUunrHSdioKuNspdggxkXIBhEQLhi8C+LJdwmHKWQ==", "dev": true }, - "node_modules/@truffle/debug-utils": { - "version": "6.0.47", - "resolved": "https://registry.npmjs.org/@truffle/debug-utils/-/debug-utils-6.0.47.tgz", - "integrity": "sha512-bUjdzLPdEKtoUCDzaXkrOoi+PbyAJlMBzGequBK8tirT7xL9bCP2Pd/WxvnmRd7AnfroxGNvXwVXWTItW5SMWQ==", + "node_modules/@truffle/contract/node_modules/eth-lib": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.8.tgz", + "integrity": "sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw==", "dev": true, "dependencies": { - "@truffle/codec": "^0.14.16", + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "xhr-request-promise": "^0.1.2" + } + }, + "node_modules/@truffle/contract/node_modules/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@truffle/contract/node_modules/web3": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.8.2.tgz", + "integrity": "sha512-92h0GdEHW9wqDICQQKyG4foZBYi0OQkyg4CRml2F7XBl/NG+fu9o6J19kzfFXzSBoA4DnJXbyRgj/RHZv5LRiw==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "web3-bzz": "1.8.2", + "web3-core": "1.8.2", + "web3-eth": "1.8.2", + "web3-eth-personal": "1.8.2", + "web3-net": "1.8.2", + "web3-shh": "1.8.2", + "web3-utils": "1.8.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-bzz": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.8.2.tgz", + "integrity": "sha512-1EEnxjPnFnvNWw3XeeKuTR8PBxYd0+XWzvaLK7OJC/Go9O8llLGxrxICbKV+8cgIE0sDRBxiYx02X+6OhoAQ9w==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@types/node": "^12.12.6", + "got": "12.1.0", + "swarm-js": "^0.1.40" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-core": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.8.2.tgz", + "integrity": "sha512-DJTVEAYcNqxkqruJE+Rxp3CIv0y5AZMwPHQmOkz/cz+MM75SIzMTc0AUdXzGyTS8xMF8h3YWMQGgGEy8SBf1PQ==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.0", + "@types/node": "^12.12.6", + "bignumber.js": "^9.0.0", + "web3-core-helpers": "1.8.2", + "web3-core-method": "1.8.2", + "web3-core-requestmanager": "1.8.2", + "web3-utils": "1.8.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-core-helpers": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.8.2.tgz", + "integrity": "sha512-6B1eLlq9JFrfealZBomd1fmlq1o4A09vrCVQSa51ANoib/jllT3atZrRDr0zt1rfI7TSZTZBXdN/aTdeN99DWw==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.8.2", + "web3-utils": "1.8.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-core-method": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.8.2.tgz", + "integrity": "sha512-1qnr5mw5wVyULzLOrk4B+ryO3gfGjGd/fx8NR+J2xCGLf1e6OSjxT9vbfuQ3fErk/NjSTWWreieYWLMhaogcRA==", + "dev": true, + "dependencies": { + "@ethersproject/transactions": "^5.6.2", + "web3-core-helpers": "1.8.2", + "web3-core-promievent": "1.8.2", + "web3-core-subscriptions": "1.8.2", + "web3-utils": "1.8.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-core-promievent": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.8.2.tgz", + "integrity": "sha512-nvkJWDVgoOSsolJldN33tKW6bKKRJX3MCPDYMwP5SUFOA/mCzDEoI88N0JFofDTXkh1k7gOqp1pvwi9heuaxGg==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-core-requestmanager": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.8.2.tgz", + "integrity": "sha512-p1d090RYs5Mu7DK1yyc3GCBVZB/03rBtFhYFoS2EruGzOWs/5Q0grgtpwS/DScdRAm8wB8mYEBhY/RKJWF6B2g==", + "dev": true, + "dependencies": { + "util": "^0.12.5", + "web3-core-helpers": "1.8.2", + "web3-providers-http": "1.8.2", + "web3-providers-ipc": "1.8.2", + "web3-providers-ws": "1.8.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-core-subscriptions": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.8.2.tgz", + "integrity": "sha512-vXQogHDmAIQcKpXvGiMddBUeP9lnKgYF64+yQJhPNE5PnWr1sAibXuIPV7mIPihpFr/n/DORRj6Wh1pUv9zaTw==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.8.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-core/node_modules/bignumber.js": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz", + "integrity": "sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/@truffle/contract/node_modules/web3-eth": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.8.2.tgz", + "integrity": "sha512-JoTiWWc4F4TInpbvDUGb0WgDYJsFhuIjJlinc5ByjWD88Gvh+GKLsRjjFdbqe5YtwIGT4NymwoC5LQd1K6u/QQ==", + "dev": true, + "dependencies": { + "web3-core": "1.8.2", + "web3-core-helpers": "1.8.2", + "web3-core-method": "1.8.2", + "web3-core-subscriptions": "1.8.2", + "web3-eth-abi": "1.8.2", + "web3-eth-accounts": "1.8.2", + "web3-eth-contract": "1.8.2", + "web3-eth-ens": "1.8.2", + "web3-eth-iban": "1.8.2", + "web3-eth-personal": "1.8.2", + "web3-net": "1.8.2", + "web3-utils": "1.8.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-eth-abi": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.8.2.tgz", + "integrity": "sha512-Om9g3kaRNjqiNPAgKwGT16y+ZwtBzRe4ZJFGjLiSs6v5I7TPNF+rRMWuKnR6jq0azQZDj6rblvKFMA49/k48Og==", + "dev": true, + "dependencies": { + "@ethersproject/abi": "^5.6.3", + "web3-utils": "1.8.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-eth-accounts": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.8.2.tgz", + "integrity": "sha512-c367Ij63VCz9YdyjiHHWLFtN85l6QghgwMQH2B1eM/p9Y5lTlTX7t/Eg/8+f1yoIStXbk2w/PYM2lk+IkbqdLA==", + "dev": true, + "dependencies": { + "@ethereumjs/common": "2.5.0", + "@ethereumjs/tx": "3.3.2", + "eth-lib": "0.2.8", + "ethereumjs-util": "^7.1.5", + "scrypt-js": "^3.0.1", + "uuid": "^9.0.0", + "web3-core": "1.8.2", + "web3-core-helpers": "1.8.2", + "web3-core-method": "1.8.2", + "web3-utils": "1.8.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-eth-contract": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.8.2.tgz", + "integrity": "sha512-ID5A25tHTSBNwOPjiXSVzxruz006ULRIDbzWTYIFTp7NJ7vXu/kynKK2ag/ObuTqBpMbobP8nXcA9b5EDkIdQA==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.0", + "web3-core": "1.8.2", + "web3-core-helpers": "1.8.2", + "web3-core-method": "1.8.2", + "web3-core-promievent": "1.8.2", + "web3-core-subscriptions": "1.8.2", + "web3-eth-abi": "1.8.2", + "web3-utils": "1.8.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-eth-ens": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.8.2.tgz", + "integrity": "sha512-PWph7C/CnqdWuu1+SH4U4zdrK4t2HNt0I4XzPYFdv9ugE8EuojselioPQXsVGvjql+Nt3jDLvQvggPqlMbvwRw==", + "dev": true, + "dependencies": { + "content-hash": "^2.5.2", + "eth-ens-namehash": "2.0.8", + "web3-core": "1.8.2", + "web3-core-helpers": "1.8.2", + "web3-core-promievent": "1.8.2", + "web3-eth-abi": "1.8.2", + "web3-eth-contract": "1.8.2", + "web3-utils": "1.8.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-eth-iban": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.8.2.tgz", + "integrity": "sha512-h3vNblDWkWMuYx93Q27TAJz6lhzpP93EiC3+45D6xoz983p6si773vntoQ+H+5aZhwglBtoiBzdh7PSSOnP/xQ==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.8.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-eth-iban/node_modules/bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "dev": true + }, + "node_modules/@truffle/contract/node_modules/web3-eth-personal": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.8.2.tgz", + "integrity": "sha512-Vg4HfwCr7doiUF/RC+Jz0wT4+cYaXcOWMAW2AHIjHX6Z7Xwa8nrURIeQgeEE62qcEHAzajyAdB1u6bJyTfuCXw==", + "dev": true, + "dependencies": { + "@types/node": "^12.12.6", + "web3-core": "1.8.2", + "web3-core-helpers": "1.8.2", + "web3-core-method": "1.8.2", + "web3-net": "1.8.2", + "web3-utils": "1.8.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-net": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.8.2.tgz", + "integrity": "sha512-1itkDMGmbgb83Dg9nporFes9/fxsU7smJ3oRXlFkg4ZHn8YJyP1MSQFPJWWwSc+GrcCFt4O5IrUTvEkHqE3xag==", + "dev": true, + "dependencies": { + "web3-core": "1.8.2", + "web3-core-method": "1.8.2", + "web3-utils": "1.8.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-providers-http": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.8.2.tgz", + "integrity": "sha512-2xY94IIEQd16+b+vIBF4IC1p7GVaz9q4EUFscvMUjtEq4ru4Atdzjs9GP+jmcoo49p70II0UV3bqQcz0TQfVyQ==", + "dev": true, + "dependencies": { + "abortcontroller-polyfill": "^1.7.3", + "cross-fetch": "^3.1.4", + "es6-promise": "^4.2.8", + "web3-core-helpers": "1.8.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-providers-ipc": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.8.2.tgz", + "integrity": "sha512-p6fqKVGFg+WiXGHWnB1hu43PbvPkDHTz4RgoEzbXugv5rtv5zfYLqm8Ba6lrJOS5ks9kGKR21a0y3NzE3u7V4w==", + "dev": true, + "dependencies": { + "oboe": "2.1.5", + "web3-core-helpers": "1.8.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-providers-ws": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.8.2.tgz", + "integrity": "sha512-3s/4K+wHgbiN+Zrp9YjMq2eqAF6QGABw7wFftPdx+m5hWImV27/MoIx57c6HffNRqZXmCHnfWWFCNHHsi7wXnA==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.8.2", + "websocket": "^1.0.32" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-shh": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.8.2.tgz", + "integrity": "sha512-uZ+3MAoNcaJsXXNCDnizKJ5viBNeHOFYsCbFhV755Uu52FswzTOw6DtE7yK9nYXMtIhiSgi7nwl1RYzP8pystw==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "web3-core": "1.8.2", + "web3-core-method": "1.8.2", + "web3-core-subscriptions": "1.8.2", + "web3-net": "1.8.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-utils": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.8.2.tgz", + "integrity": "sha512-v7j6xhfLQfY7xQDrUP0BKbaNrmZ2/+egbqP9q3KYmOiPpnvAfol+32slgL0WX/5n8VPvKCK5EZ1HGrAVICSToA==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereumjs-util": "^7.1.0", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-utils/node_modules/bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "dev": true + }, + "node_modules/@truffle/debug-utils": { + "version": "6.0.48", + "resolved": "https://registry.npmjs.org/@truffle/debug-utils/-/debug-utils-6.0.48.tgz", + "integrity": "sha512-HdK/7eH5EFrcTPeZVEgKaKkkzuZ4xsrH8yw+EoLEsScLsOEuQeKynY61NctjuU93voATWrYmV99Sfb/MRq2i2g==", + "dev": true, + "dependencies": { + "@truffle/codec": "^0.14.17", "@trufflesuite/chromafi": "^3.0.0", "bn.js": "^5.1.3", "chalk": "^2.4.2", @@ -2565,9 +3128,9 @@ "dev": true }, "node_modules/@truffle/interface-adapter": { - "version": "0.5.30", - "resolved": "https://registry.npmjs.org/@truffle/interface-adapter/-/interface-adapter-0.5.30.tgz", - "integrity": "sha512-wyCcESeZJBkAfuSGU8GHCusIWDUDyQjJZMcyShv59ZTSAwQR7xx0+a0Q1LlS532G/pGFLYe2VzKSY1pRHRwgug==", + "version": "0.5.32", + "resolved": "https://registry.npmjs.org/@truffle/interface-adapter/-/interface-adapter-0.5.32.tgz", + "integrity": "sha512-7Hgmdb4nJUcWtq4vvgWY7Mr2RLOTOp5FZaWyMiFmjkcEEhDlezm2QstALWAXgT0W6q7tDmDBpw3vTIFenRhHBA==", "dev": true, "dependencies": { "bn.js": "^5.1.3", @@ -2575,12 +3138,384 @@ "web3": "1.8.2" } }, + "node_modules/@truffle/interface-adapter/node_modules/bignumber.js": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz", + "integrity": "sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/@truffle/interface-adapter/node_modules/bn.js": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", "dev": true }, + "node_modules/@truffle/interface-adapter/node_modules/eth-lib": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.8.tgz", + "integrity": "sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "xhr-request-promise": "^0.1.2" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/eth-lib/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/@truffle/interface-adapter/node_modules/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.8.2.tgz", + "integrity": "sha512-92h0GdEHW9wqDICQQKyG4foZBYi0OQkyg4CRml2F7XBl/NG+fu9o6J19kzfFXzSBoA4DnJXbyRgj/RHZv5LRiw==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "web3-bzz": "1.8.2", + "web3-core": "1.8.2", + "web3-eth": "1.8.2", + "web3-eth-personal": "1.8.2", + "web3-net": "1.8.2", + "web3-shh": "1.8.2", + "web3-utils": "1.8.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-bzz": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.8.2.tgz", + "integrity": "sha512-1EEnxjPnFnvNWw3XeeKuTR8PBxYd0+XWzvaLK7OJC/Go9O8llLGxrxICbKV+8cgIE0sDRBxiYx02X+6OhoAQ9w==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@types/node": "^12.12.6", + "got": "12.1.0", + "swarm-js": "^0.1.40" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-core": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.8.2.tgz", + "integrity": "sha512-DJTVEAYcNqxkqruJE+Rxp3CIv0y5AZMwPHQmOkz/cz+MM75SIzMTc0AUdXzGyTS8xMF8h3YWMQGgGEy8SBf1PQ==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.0", + "@types/node": "^12.12.6", + "bignumber.js": "^9.0.0", + "web3-core-helpers": "1.8.2", + "web3-core-method": "1.8.2", + "web3-core-requestmanager": "1.8.2", + "web3-utils": "1.8.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-core-helpers": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.8.2.tgz", + "integrity": "sha512-6B1eLlq9JFrfealZBomd1fmlq1o4A09vrCVQSa51ANoib/jllT3atZrRDr0zt1rfI7TSZTZBXdN/aTdeN99DWw==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.8.2", + "web3-utils": "1.8.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-core-method": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.8.2.tgz", + "integrity": "sha512-1qnr5mw5wVyULzLOrk4B+ryO3gfGjGd/fx8NR+J2xCGLf1e6OSjxT9vbfuQ3fErk/NjSTWWreieYWLMhaogcRA==", + "dev": true, + "dependencies": { + "@ethersproject/transactions": "^5.6.2", + "web3-core-helpers": "1.8.2", + "web3-core-promievent": "1.8.2", + "web3-core-subscriptions": "1.8.2", + "web3-utils": "1.8.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-core-promievent": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.8.2.tgz", + "integrity": "sha512-nvkJWDVgoOSsolJldN33tKW6bKKRJX3MCPDYMwP5SUFOA/mCzDEoI88N0JFofDTXkh1k7gOqp1pvwi9heuaxGg==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-core-requestmanager": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.8.2.tgz", + "integrity": "sha512-p1d090RYs5Mu7DK1yyc3GCBVZB/03rBtFhYFoS2EruGzOWs/5Q0grgtpwS/DScdRAm8wB8mYEBhY/RKJWF6B2g==", + "dev": true, + "dependencies": { + "util": "^0.12.5", + "web3-core-helpers": "1.8.2", + "web3-providers-http": "1.8.2", + "web3-providers-ipc": "1.8.2", + "web3-providers-ws": "1.8.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-core-subscriptions": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.8.2.tgz", + "integrity": "sha512-vXQogHDmAIQcKpXvGiMddBUeP9lnKgYF64+yQJhPNE5PnWr1sAibXuIPV7mIPihpFr/n/DORRj6Wh1pUv9zaTw==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.8.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-eth": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.8.2.tgz", + "integrity": "sha512-JoTiWWc4F4TInpbvDUGb0WgDYJsFhuIjJlinc5ByjWD88Gvh+GKLsRjjFdbqe5YtwIGT4NymwoC5LQd1K6u/QQ==", + "dev": true, + "dependencies": { + "web3-core": "1.8.2", + "web3-core-helpers": "1.8.2", + "web3-core-method": "1.8.2", + "web3-core-subscriptions": "1.8.2", + "web3-eth-abi": "1.8.2", + "web3-eth-accounts": "1.8.2", + "web3-eth-contract": "1.8.2", + "web3-eth-ens": "1.8.2", + "web3-eth-iban": "1.8.2", + "web3-eth-personal": "1.8.2", + "web3-net": "1.8.2", + "web3-utils": "1.8.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-eth-abi": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.8.2.tgz", + "integrity": "sha512-Om9g3kaRNjqiNPAgKwGT16y+ZwtBzRe4ZJFGjLiSs6v5I7TPNF+rRMWuKnR6jq0azQZDj6rblvKFMA49/k48Og==", + "dev": true, + "dependencies": { + "@ethersproject/abi": "^5.6.3", + "web3-utils": "1.8.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-eth-accounts": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.8.2.tgz", + "integrity": "sha512-c367Ij63VCz9YdyjiHHWLFtN85l6QghgwMQH2B1eM/p9Y5lTlTX7t/Eg/8+f1yoIStXbk2w/PYM2lk+IkbqdLA==", + "dev": true, + "dependencies": { + "@ethereumjs/common": "2.5.0", + "@ethereumjs/tx": "3.3.2", + "eth-lib": "0.2.8", + "ethereumjs-util": "^7.1.5", + "scrypt-js": "^3.0.1", + "uuid": "^9.0.0", + "web3-core": "1.8.2", + "web3-core-helpers": "1.8.2", + "web3-core-method": "1.8.2", + "web3-utils": "1.8.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-eth-contract": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.8.2.tgz", + "integrity": "sha512-ID5A25tHTSBNwOPjiXSVzxruz006ULRIDbzWTYIFTp7NJ7vXu/kynKK2ag/ObuTqBpMbobP8nXcA9b5EDkIdQA==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.0", + "web3-core": "1.8.2", + "web3-core-helpers": "1.8.2", + "web3-core-method": "1.8.2", + "web3-core-promievent": "1.8.2", + "web3-core-subscriptions": "1.8.2", + "web3-eth-abi": "1.8.2", + "web3-utils": "1.8.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-eth-ens": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.8.2.tgz", + "integrity": "sha512-PWph7C/CnqdWuu1+SH4U4zdrK4t2HNt0I4XzPYFdv9ugE8EuojselioPQXsVGvjql+Nt3jDLvQvggPqlMbvwRw==", + "dev": true, + "dependencies": { + "content-hash": "^2.5.2", + "eth-ens-namehash": "2.0.8", + "web3-core": "1.8.2", + "web3-core-helpers": "1.8.2", + "web3-core-promievent": "1.8.2", + "web3-eth-abi": "1.8.2", + "web3-eth-contract": "1.8.2", + "web3-utils": "1.8.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-eth-iban": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.8.2.tgz", + "integrity": "sha512-h3vNblDWkWMuYx93Q27TAJz6lhzpP93EiC3+45D6xoz983p6si773vntoQ+H+5aZhwglBtoiBzdh7PSSOnP/xQ==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.8.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-eth-personal": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.8.2.tgz", + "integrity": "sha512-Vg4HfwCr7doiUF/RC+Jz0wT4+cYaXcOWMAW2AHIjHX6Z7Xwa8nrURIeQgeEE62qcEHAzajyAdB1u6bJyTfuCXw==", + "dev": true, + "dependencies": { + "@types/node": "^12.12.6", + "web3-core": "1.8.2", + "web3-core-helpers": "1.8.2", + "web3-core-method": "1.8.2", + "web3-net": "1.8.2", + "web3-utils": "1.8.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-net": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.8.2.tgz", + "integrity": "sha512-1itkDMGmbgb83Dg9nporFes9/fxsU7smJ3oRXlFkg4ZHn8YJyP1MSQFPJWWwSc+GrcCFt4O5IrUTvEkHqE3xag==", + "dev": true, + "dependencies": { + "web3-core": "1.8.2", + "web3-core-method": "1.8.2", + "web3-utils": "1.8.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-providers-http": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.8.2.tgz", + "integrity": "sha512-2xY94IIEQd16+b+vIBF4IC1p7GVaz9q4EUFscvMUjtEq4ru4Atdzjs9GP+jmcoo49p70II0UV3bqQcz0TQfVyQ==", + "dev": true, + "dependencies": { + "abortcontroller-polyfill": "^1.7.3", + "cross-fetch": "^3.1.4", + "es6-promise": "^4.2.8", + "web3-core-helpers": "1.8.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-providers-ipc": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.8.2.tgz", + "integrity": "sha512-p6fqKVGFg+WiXGHWnB1hu43PbvPkDHTz4RgoEzbXugv5rtv5zfYLqm8Ba6lrJOS5ks9kGKR21a0y3NzE3u7V4w==", + "dev": true, + "dependencies": { + "oboe": "2.1.5", + "web3-core-helpers": "1.8.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-providers-ws": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.8.2.tgz", + "integrity": "sha512-3s/4K+wHgbiN+Zrp9YjMq2eqAF6QGABw7wFftPdx+m5hWImV27/MoIx57c6HffNRqZXmCHnfWWFCNHHsi7wXnA==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.8.2", + "websocket": "^1.0.32" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-shh": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.8.2.tgz", + "integrity": "sha512-uZ+3MAoNcaJsXXNCDnizKJ5viBNeHOFYsCbFhV755Uu52FswzTOw6DtE7yK9nYXMtIhiSgi7nwl1RYzP8pystw==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "web3-core": "1.8.2", + "web3-core-method": "1.8.2", + "web3-core-subscriptions": "1.8.2", + "web3-net": "1.8.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-utils": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.8.2.tgz", + "integrity": "sha512-v7j6xhfLQfY7xQDrUP0BKbaNrmZ2/+egbqP9q3KYmOiPpnvAfol+32slgL0WX/5n8VPvKCK5EZ1HGrAVICSToA==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereumjs-util": "^7.1.0", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/@trufflesuite/chromafi": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@trufflesuite/chromafi/-/chromafi-3.0.0.tgz", @@ -2606,12 +3541,6 @@ "node": ">=4" } }, - "node_modules/@types/async-eventemitter": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@types/async-eventemitter/-/async-eventemitter-0.2.1.tgz", - "integrity": "sha512-M2P4Ng26QbAeITiH7w1d7OxtldgfAe0wobpyJzVK/XOb0cUGKU2R4pfAhqcJBXAe2ife5ZOhSv4wk7p+ffURtg==", - "dev": true - }, "node_modules/@types/bignumber.js": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/@types/bignumber.js/-/bignumber.js-5.0.0.tgz", @@ -2644,9 +3573,9 @@ } }, "node_modules/@types/chai": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.4.tgz", - "integrity": "sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz", + "integrity": "sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==", "dev": true }, "node_modules/@types/concat-stream": { @@ -2746,6 +3675,22 @@ "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", "dev": true }, + "node_modules/@types/readable-stream": { + "version": "2.3.15", + "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-2.3.15.tgz", + "integrity": "sha512-oM5JSKQCcICF1wvGgmecmHldZ48OZamtMxcGGVICOJA8o8cahXC1zEVAif8iwoc5j8etxFaRFnf095+CDsuoFQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "safe-buffer": "~5.1.1" + } + }, + "node_modules/@types/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, "node_modules/@types/responselike": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", @@ -3171,22 +4116,10 @@ } }, "node_modules/async": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "dev": true, - "dependencies": { - "lodash": "^4.17.14" - } - }, - "node_modules/async-eventemitter": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/async-eventemitter/-/async-eventemitter-0.2.4.tgz", - "integrity": "sha512-pd20BwL7Yt1zwDFy+8MX8F1+WCT8aQeKj0kQnTrH9WaeRETlRamVhD0JtRPmrV4GfOJ2F9CvdQkZeZhnh2TuHw==", - "dev": true, - "dependencies": { - "async": "^2.4.0" - } + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==", + "dev": true }, "node_modules/async-limiter": { "version": "1.0.1", @@ -3318,24 +4251,12 @@ } }, "node_modules/bigint-crypto-utils": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/bigint-crypto-utils/-/bigint-crypto-utils-3.1.8.tgz", - "integrity": "sha512-+VMV9Laq8pXLBKKKK49nOoq9bfR3j7NNQAtbA617a4nw9bVLo8rsqkKMBgM2AJWlNX9fEIyYaYX+d0laqYV4tw==", - "dev": true, - "dependencies": { - "bigint-mod-arith": "^3.1.0" - }, - "engines": { - "node": ">=10.4.0" - } - }, - "node_modules/bigint-mod-arith": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bigint-mod-arith/-/bigint-mod-arith-3.1.2.tgz", - "integrity": "sha512-nx8J8bBeiRR+NlsROFH9jHswW5HO8mgfOSqW0AmjicMMvaONDa8AO+5ViKDUUNytBPWiwfvZP4/Bj4Y3lUfvgQ==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/bigint-crypto-utils/-/bigint-crypto-utils-3.2.2.tgz", + "integrity": "sha512-U1RbE3aX9ayCUVcIPHuPDPKcK3SFOXf93J1UK/iHlJuQB7bhagPIX06/CLpLEsDThJ7KA4Dhrnzynl+d2weTiw==", "dev": true, "engines": { - "node": ">=10.4.0" + "node": ">=14.0.0" } }, "node_modules/bignumber.js": { @@ -3723,6 +4644,15 @@ "node": ">=6" } }, + "node_modules/case": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/case/-/case-1.6.3.tgz", + "integrity": "sha512-mzDSXIPaFwVDvZAHqZ9VlbyF4yyXRuX6IvB06WvPYkqJVO24kX1PPhv9bfpKNFZyxYFmmgo03HUiD8iklmJYRQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -3974,16 +4904,16 @@ "dev": true }, "node_modules/classic-level": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/classic-level/-/classic-level-1.2.0.tgz", - "integrity": "sha512-qw5B31ANxSluWz9xBzklRWTUAJ1SXIdaVKTVS7HcTGKOAmExx65Wo5BUICW+YGORe2FOUaDghoI9ZDxj82QcFg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/classic-level/-/classic-level-1.3.0.tgz", + "integrity": "sha512-iwFAJQYtqRTRM0F6L8h4JCt00ZSGdOyqh7yVrhhjrOpFhmBjNlRUey64MCiyo6UmQHMJ+No3c81nujPv+n9yrg==", "dev": true, "hasInstallScript": true, "dependencies": { "abstract-level": "^1.0.2", "catering": "^2.1.0", "module-error": "^1.0.1", - "napi-macros": "~2.0.0", + "napi-macros": "^2.2.2", "node-gyp-build": "^4.3.0" }, "engines": { @@ -4146,9 +5076,9 @@ "dev": true }, "node_modules/commander": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.0.tgz", - "integrity": "sha512-zS5PnTI22FIRM6ylNW8G4Ap0IEOyk62fhLSD0+uHRT9McRCLGpkVNvao4bjimpK/GShynyQkFFxHhwMcETmduA==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", "dev": true, "engines": { "node": ">=14" @@ -4288,9 +5218,9 @@ } }, "node_modules/cosmiconfig": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.1.0.tgz", - "integrity": "sha512-0tLZ9URlPGU7JsKq0DQOQ3FoRsYX8xDZ7xMiATQfaiGMz7EHowNkbU9u1coAOmnh9p/1ySpm0RB3JNWRXM5GCg==", + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.1.3.tgz", + "integrity": "sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==", "dev": true, "dependencies": { "import-fresh": "^3.2.1", @@ -4816,14 +5746,14 @@ } }, "node_modules/domutils": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", - "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", "dev": true, "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", - "domhandler": "^5.0.1" + "domhandler": "^5.0.3" }, "funding": { "url": "https://github.com/fb55/domutils?sponsor=1" @@ -4915,9 +5845,9 @@ } }, "node_modules/entities": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", - "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "dev": true, "engines": { "node": ">=0.12" @@ -5200,15 +6130,15 @@ } }, "node_modules/eslint": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.36.0.tgz", - "integrity": "sha512-Y956lmS7vDqomxlaaQAHVmeb4tNMp2FWIvU/RnU5BD3IKMD/MJPr76xdyr68P8tV1iNMvN2mRK0yy3c+UjL+bw==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.39.0.tgz", + "integrity": "sha512-mwiok6cy7KTW7rBpo05k6+p4YVZByLNjAZ/ACB9DRCu4YDRwjXI01tWHp6KAUWelsBetTxKK/2sHB0vdS8Z2Og==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.1", - "@eslint/js": "8.36.0", + "@eslint/eslintrc": "^2.0.2", + "@eslint/js": "8.39.0", "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -5218,9 +6148,9 @@ "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.5.0", + "eslint-scope": "^7.2.0", + "eslint-visitor-keys": "^3.4.0", + "espree": "^9.5.1", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -5257,9 +6187,9 @@ } }, "node_modules/eslint-config-prettier": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.7.0.tgz", - "integrity": "sha512-HHVXLSlVUhMSmyW4ZzEuvjpwqamgmlfkutD53cYXLikh4pt/modINRcCIApJ84czDxM4GZInwUrromsDdTImTA==", + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz", + "integrity": "sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==", "dev": true, "bin": { "eslint-config-prettier": "bin/cli.js" @@ -5269,9 +6199,9 @@ } }, "node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", + "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", @@ -5279,15 +6209,21 @@ }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", + "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint/node_modules/ansi-regex": { @@ -5470,14 +6406,14 @@ } }, "node_modules/espree": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.0.tgz", - "integrity": "sha512-JPbJGhKc47++oo4JkEoTe2wjy4fmMwvFpgJT9cQzmfXKp22Dr6Hf1tdCteLz1h0P3t+mGvWZ+4Uankvh8+c6zw==", + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", + "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", "dev": true, "dependencies": { "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -7165,9 +8101,9 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, "node_modules/grapheme-splitter": { @@ -7257,23 +8193,23 @@ } }, "node_modules/hardhat": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.13.0.tgz", - "integrity": "sha512-ZlzBOLML1QGlm6JWyVAG8lVTEAoOaVm1in/RU2zoGAnYEoD1Rp4T+ZMvrLNhHaaeS9hfjJ1gJUBfiDr4cx+htQ==", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.14.0.tgz", + "integrity": "sha512-73jsInY4zZahMSVFurSK+5TNCJTXMv+vemvGia0Ac34Mm19fYp6vEPVGF3sucbumszsYxiTT2TbS8Ii2dsDSoQ==", "dev": true, "dependencies": { "@ethersproject/abi": "^5.1.2", "@metamask/eth-sig-util": "^4.0.0", - "@nomicfoundation/ethereumjs-block": "^4.0.0", - "@nomicfoundation/ethereumjs-blockchain": "^6.0.0", - "@nomicfoundation/ethereumjs-common": "^3.0.0", - "@nomicfoundation/ethereumjs-evm": "^1.0.0", - "@nomicfoundation/ethereumjs-rlp": "^4.0.0", - "@nomicfoundation/ethereumjs-statemanager": "^1.0.0", - "@nomicfoundation/ethereumjs-trie": "^5.0.0", - "@nomicfoundation/ethereumjs-tx": "^4.0.0", - "@nomicfoundation/ethereumjs-util": "^8.0.0", - "@nomicfoundation/ethereumjs-vm": "^6.0.0", + "@nomicfoundation/ethereumjs-block": "5.0.1", + "@nomicfoundation/ethereumjs-blockchain": "7.0.1", + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-evm": "2.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-statemanager": "2.0.1", + "@nomicfoundation/ethereumjs-trie": "6.0.1", + "@nomicfoundation/ethereumjs-tx": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "@nomicfoundation/ethereumjs-vm": "7.0.1", "@nomicfoundation/solidity-analyzer": "^0.1.0", "@sentry/node": "^5.18.1", "@types/bn.js": "^5.1.0", @@ -7749,9 +8685,9 @@ "dev": true }, "node_modules/htmlparser2": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz", - "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", "dev": true, "funding": [ "https://github.com/fb55/htmlparser2?sponsor=1", @@ -7762,9 +8698,9 @@ ], "dependencies": { "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", + "domhandler": "^5.0.3", "domutils": "^3.0.1", - "entities": "^4.3.0" + "entities": "^4.4.0" } }, "node_modules/http-basic": { @@ -8491,9 +9427,9 @@ "dev": true }, "node_modules/js-sdsl": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", - "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", + "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", "dev": true, "funding": { "type": "opencollective", @@ -9337,9 +10273,9 @@ } }, "node_modules/mixme": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mixme/-/mixme-0.5.5.tgz", - "integrity": "sha512-/6IupbRx32s7jjEwHcycXikJwFD5UujbVNuJFkeKLYje+92OvtuPniF6JhnFm5JCTDUhS+kYK3W/4BWYQYXz7w==", + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/mixme/-/mixme-0.5.9.tgz", + "integrity": "sha512-VC5fg6ySUscaWUpI4gxCBTQMH2RdUpNrk+MsbpCYtIvf9SBJdiUey4qE7BXviJsJR4nDQxCZ+3yaYNW3guz/Pw==", "dev": true, "engines": { "node": ">= 8.0.0" @@ -9758,9 +10694,9 @@ } }, "node_modules/napi-macros": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz", - "integrity": "sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.2.2.tgz", + "integrity": "sha512-hmEVtAGYzVQpCKdbQea4skABsdXW4RUh5t5mJ2zzqowJS2OyXZTU1KhDVFhx+NlWZ4ap9mqR9TcDO3LTTttd+g==", "dev": true }, "node_modules/natural-compare": { @@ -10035,15 +10971,16 @@ } }, "node_modules/object.getownpropertydescriptors": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.5.tgz", - "integrity": "sha512-yDNzckpM6ntyQiGTik1fKV1DcVDRS+w8bvpWNCBanvH5LfRX9O8WTHqQzG4RZwRAM4I0oU7TV11Lj5v0g20ibw==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.6.tgz", + "integrity": "sha512-lq+61g26E/BgHv0ZTFgRvi7NMEPuAxLkFU7rukXjc/AlwH4Am5xXVnIXy3un1bg/JPbXHrixRkK1itUzzPiIjQ==", "dev": true, "dependencies": { "array.prototype.reduce": "^1.0.5", "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.21.2", + "safe-array-concat": "^1.0.0" }, "engines": { "node": ">= 0.8" @@ -10551,9 +11488,9 @@ } }, "node_modules/prettier": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", - "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", "dev": true, "bin": { "prettier": "bin-prettier.js" @@ -10924,14 +11861,14 @@ "dev": true }, "node_modules/regexp.prototype.flags": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", - "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", + "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" + "define-properties": "^1.2.0", + "functions-have-names": "^1.2.3" }, "engines": { "node": ">= 0.4" @@ -11272,6 +12209,30 @@ "integrity": "sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA==", "dev": true }, + "node_modules/safe-array-concat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.0.tgz", + "integrity": "sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-array-concat/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -11337,12 +12298,6 @@ "istanbul": "lib/cli.js" } }, - "node_modules/sc-istanbul/node_modules/async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==", - "dev": true - }, "node_modules/sc-istanbul/node_modules/esprima": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", @@ -11433,9 +12388,9 @@ } }, "node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -13963,18 +14918,18 @@ "dev": true }, "node_modules/tty-table": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/tty-table/-/tty-table-4.1.6.tgz", - "integrity": "sha512-kRj5CBzOrakV4VRRY5kUWbNYvo/FpOsz65DzI5op9P+cHov3+IqPbo1JE1ZnQGkHdZgNFDsrEjrfqqy/Ply9fw==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/tty-table/-/tty-table-4.2.1.tgz", + "integrity": "sha512-xz0uKo+KakCQ+Dxj1D/tKn2FSyreSYWzdkL/BYhgN6oMW808g8QRMuh1atAV9fjTPbWBjfbkKQpI/5rEcnAc7g==", "dev": true, "dependencies": { "chalk": "^4.1.2", - "csv": "^5.5.0", - "kleur": "^4.1.4", + "csv": "^5.5.3", + "kleur": "^4.1.5", "smartwrap": "^2.0.2", - "strip-ansi": "^6.0.0", + "strip-ansi": "^6.0.1", "wcwidth": "^1.0.1", - "yargs": "^17.1.1" + "yargs": "^17.7.1" }, "bin": { "tty-table": "adapters/terminal-adapter.js" @@ -14220,15 +15175,15 @@ "dev": true }, "node_modules/undici": { - "version": "5.21.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.21.0.tgz", - "integrity": "sha512-HOjK8l6a57b2ZGXOcUsI5NLfoTrfmbOl90ixJDl0AEFG4wgHNDQxtZy15/ZQp7HhjkpaGlp/eneMgtsu1dIlUA==", + "version": "5.22.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.0.tgz", + "integrity": "sha512-fR9RXCc+6Dxav4P9VV/sp5w3eFiSdOjJYsbtWfd4s5L5C4ogyuVpdKIVHeW0vV1MloM65/f7W45nR9ZxwVdyiA==", "dev": true, "dependencies": { "busboy": "^1.6.0" }, "engines": { - "node": ">=12.18" + "node": ">=14.0" } }, "node_modules/universalify": { @@ -14384,28 +15339,28 @@ } }, "node_modules/web3": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3/-/web3-1.8.2.tgz", - "integrity": "sha512-92h0GdEHW9wqDICQQKyG4foZBYi0OQkyg4CRml2F7XBl/NG+fu9o6J19kzfFXzSBoA4DnJXbyRgj/RHZv5LRiw==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.9.0.tgz", + "integrity": "sha512-E9IvVy/d2ozfQQsCiV+zh/LmlZGv9fQxI0UedDVjm87yOKf4AYbBNEn1iWtHveiGzAk2CEMZMUzAZzaQNSSYog==", "dev": true, "hasInstallScript": true, "dependencies": { - "web3-bzz": "1.8.2", - "web3-core": "1.8.2", - "web3-eth": "1.8.2", - "web3-eth-personal": "1.8.2", - "web3-net": "1.8.2", - "web3-shh": "1.8.2", - "web3-utils": "1.8.2" + "web3-bzz": "1.9.0", + "web3-core": "1.9.0", + "web3-eth": "1.9.0", + "web3-eth-personal": "1.9.0", + "web3-net": "1.9.0", + "web3-shh": "1.9.0", + "web3-utils": "1.9.0" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-bzz": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.8.2.tgz", - "integrity": "sha512-1EEnxjPnFnvNWw3XeeKuTR8PBxYd0+XWzvaLK7OJC/Go9O8llLGxrxICbKV+8cgIE0sDRBxiYx02X+6OhoAQ9w==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.9.0.tgz", + "integrity": "sha512-9Zli9dikX8GdHwBb5/WPzpSVuy3EWMKY3P4EokCQra31fD7DLizqAAaTUsFwnK7xYkw5ogpHgelw9uKHHzNajg==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -14418,56 +15373,56 @@ } }, "node_modules/web3-core": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.8.2.tgz", - "integrity": "sha512-DJTVEAYcNqxkqruJE+Rxp3CIv0y5AZMwPHQmOkz/cz+MM75SIzMTc0AUdXzGyTS8xMF8h3YWMQGgGEy8SBf1PQ==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.9.0.tgz", + "integrity": "sha512-DZ+TPmq/ZLlx4LSVzFgrHCP/QFpKDbGWO4HoquZSdu24cjk5SZ+FEU1SZB2OaK3/bgBh+25mRbmv8y56ysUu1w==", "dev": true, "dependencies": { - "@types/bn.js": "^5.1.0", + "@types/bn.js": "^5.1.1", "@types/node": "^12.12.6", "bignumber.js": "^9.0.0", - "web3-core-helpers": "1.8.2", - "web3-core-method": "1.8.2", - "web3-core-requestmanager": "1.8.2", - "web3-utils": "1.8.2" + "web3-core-helpers": "1.9.0", + "web3-core-method": "1.9.0", + "web3-core-requestmanager": "1.9.0", + "web3-utils": "1.9.0" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-core-helpers": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.8.2.tgz", - "integrity": "sha512-6B1eLlq9JFrfealZBomd1fmlq1o4A09vrCVQSa51ANoib/jllT3atZrRDr0zt1rfI7TSZTZBXdN/aTdeN99DWw==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.9.0.tgz", + "integrity": "sha512-NeJzylAp9Yj9xAt2uTT+kyug3X0DLnfBdnAcGZuY6HhoNPDIfQRA9CkJjLngVRlGTLZGjNp9x9eR+RyZQgUlXg==", "dev": true, "dependencies": { - "web3-eth-iban": "1.8.2", - "web3-utils": "1.8.2" + "web3-eth-iban": "1.9.0", + "web3-utils": "1.9.0" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-core-method": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.8.2.tgz", - "integrity": "sha512-1qnr5mw5wVyULzLOrk4B+ryO3gfGjGd/fx8NR+J2xCGLf1e6OSjxT9vbfuQ3fErk/NjSTWWreieYWLMhaogcRA==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.9.0.tgz", + "integrity": "sha512-sswbNsY2xRBBhGeaLt9c/eDc+0yDDhi6keUBAkgIRa9ueSx/VKzUY9HMqiV6bXDcGT2fJyejq74FfEB4lc/+/w==", "dev": true, "dependencies": { "@ethersproject/transactions": "^5.6.2", - "web3-core-helpers": "1.8.2", - "web3-core-promievent": "1.8.2", - "web3-core-subscriptions": "1.8.2", - "web3-utils": "1.8.2" + "web3-core-helpers": "1.9.0", + "web3-core-promievent": "1.9.0", + "web3-core-subscriptions": "1.9.0", + "web3-utils": "1.9.0" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-core-promievent": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.8.2.tgz", - "integrity": "sha512-nvkJWDVgoOSsolJldN33tKW6bKKRJX3MCPDYMwP5SUFOA/mCzDEoI88N0JFofDTXkh1k7gOqp1pvwi9heuaxGg==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.9.0.tgz", + "integrity": "sha512-PHG1Mn23IGwMZhnPDN8dETKypqsFbHfiyRqP+XsVMPmTHkVfzDQTCBU/c2r6hUktBDoGKut5xZQpGfhFk71KbQ==", "dev": true, "dependencies": { "eventemitter3": "4.0.4" @@ -14477,29 +15432,29 @@ } }, "node_modules/web3-core-requestmanager": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.8.2.tgz", - "integrity": "sha512-p1d090RYs5Mu7DK1yyc3GCBVZB/03rBtFhYFoS2EruGzOWs/5Q0grgtpwS/DScdRAm8wB8mYEBhY/RKJWF6B2g==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.9.0.tgz", + "integrity": "sha512-hcJ5PCtTIJpj+8qWxoseqlCovDo94JJjTX7dZOLXgwp8ah7E3WRYozhGyZocerx+KebKyg1mCQIhkDpMwjfo9Q==", "dev": true, "dependencies": { "util": "^0.12.5", - "web3-core-helpers": "1.8.2", - "web3-providers-http": "1.8.2", - "web3-providers-ipc": "1.8.2", - "web3-providers-ws": "1.8.2" + "web3-core-helpers": "1.9.0", + "web3-providers-http": "1.9.0", + "web3-providers-ipc": "1.9.0", + "web3-providers-ws": "1.9.0" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-core-subscriptions": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.8.2.tgz", - "integrity": "sha512-vXQogHDmAIQcKpXvGiMddBUeP9lnKgYF64+yQJhPNE5PnWr1sAibXuIPV7mIPihpFr/n/DORRj6Wh1pUv9zaTw==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.9.0.tgz", + "integrity": "sha512-MaIo29yz7hTV8X8bioclPDbHFOVuHmnbMv+D3PDH12ceJFJAXGyW8GL5KU1DYyWIj4TD1HM4WknyVA/YWBiiLA==", "dev": true, "dependencies": { "eventemitter3": "4.0.4", - "web3-core-helpers": "1.8.2" + "web3-core-helpers": "1.9.0" }, "engines": { "node": ">=8.0.0" @@ -14515,45 +15470,45 @@ } }, "node_modules/web3-eth": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.8.2.tgz", - "integrity": "sha512-JoTiWWc4F4TInpbvDUGb0WgDYJsFhuIjJlinc5ByjWD88Gvh+GKLsRjjFdbqe5YtwIGT4NymwoC5LQd1K6u/QQ==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.9.0.tgz", + "integrity": "sha512-c5gSWk9bLNr6VPATHmZ1n7LTIefIZQnJMzfnvkoBcIFGKJbGmsuRhv6lEXsKdAO/FlqYnSbaw3fOq1fVFiIOFQ==", "dev": true, "dependencies": { - "web3-core": "1.8.2", - "web3-core-helpers": "1.8.2", - "web3-core-method": "1.8.2", - "web3-core-subscriptions": "1.8.2", - "web3-eth-abi": "1.8.2", - "web3-eth-accounts": "1.8.2", - "web3-eth-contract": "1.8.2", - "web3-eth-ens": "1.8.2", - "web3-eth-iban": "1.8.2", - "web3-eth-personal": "1.8.2", - "web3-net": "1.8.2", - "web3-utils": "1.8.2" + "web3-core": "1.9.0", + "web3-core-helpers": "1.9.0", + "web3-core-method": "1.9.0", + "web3-core-subscriptions": "1.9.0", + "web3-eth-abi": "1.9.0", + "web3-eth-accounts": "1.9.0", + "web3-eth-contract": "1.9.0", + "web3-eth-ens": "1.9.0", + "web3-eth-iban": "1.9.0", + "web3-eth-personal": "1.9.0", + "web3-net": "1.9.0", + "web3-utils": "1.9.0" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-eth-abi": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.8.2.tgz", - "integrity": "sha512-Om9g3kaRNjqiNPAgKwGT16y+ZwtBzRe4ZJFGjLiSs6v5I7TPNF+rRMWuKnR6jq0azQZDj6rblvKFMA49/k48Og==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.9.0.tgz", + "integrity": "sha512-0BLQ3FKMrzJkA930jOX3fMaybAyubk06HChclLpiR0NWmgWXm1tmBrJdkyRy2ZTZpmfuZc9xTFRfl0yZID1voA==", "dev": true, "dependencies": { "@ethersproject/abi": "^5.6.3", - "web3-utils": "1.8.2" + "web3-utils": "1.9.0" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-eth-accounts": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.8.2.tgz", - "integrity": "sha512-c367Ij63VCz9YdyjiHHWLFtN85l6QghgwMQH2B1eM/p9Y5lTlTX7t/Eg/8+f1yoIStXbk2w/PYM2lk+IkbqdLA==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.9.0.tgz", + "integrity": "sha512-VeIZVevmnSll0AC1k5F/y398ZE89d1SRuYk8IewLUhL/tVAsFEsjl2SGgm0+aDcHmgPrkW+qsCJ+C7rWg/N4ZA==", "dev": true, "dependencies": { "@ethereumjs/common": "2.5.0", @@ -14562,10 +15517,10 @@ "ethereumjs-util": "^7.1.5", "scrypt-js": "^3.0.1", "uuid": "^9.0.0", - "web3-core": "1.8.2", - "web3-core-helpers": "1.8.2", - "web3-core-method": "1.8.2", - "web3-utils": "1.8.2" + "web3-core": "1.9.0", + "web3-core-helpers": "1.9.0", + "web3-core-method": "1.9.0", + "web3-utils": "1.9.0" }, "engines": { "node": ">=8.0.0" @@ -14592,51 +15547,51 @@ } }, "node_modules/web3-eth-contract": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.8.2.tgz", - "integrity": "sha512-ID5A25tHTSBNwOPjiXSVzxruz006ULRIDbzWTYIFTp7NJ7vXu/kynKK2ag/ObuTqBpMbobP8nXcA9b5EDkIdQA==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.9.0.tgz", + "integrity": "sha512-+j26hpSaEtAdUed0TN5rnc+YZOcjPxMjFX4ZBKatvFkImdbVv/tzTvcHlltubSpgb2ZLyZ89lSL6phKYwd2zNQ==", "dev": true, "dependencies": { - "@types/bn.js": "^5.1.0", - "web3-core": "1.8.2", - "web3-core-helpers": "1.8.2", - "web3-core-method": "1.8.2", - "web3-core-promievent": "1.8.2", - "web3-core-subscriptions": "1.8.2", - "web3-eth-abi": "1.8.2", - "web3-utils": "1.8.2" + "@types/bn.js": "^5.1.1", + "web3-core": "1.9.0", + "web3-core-helpers": "1.9.0", + "web3-core-method": "1.9.0", + "web3-core-promievent": "1.9.0", + "web3-core-subscriptions": "1.9.0", + "web3-eth-abi": "1.9.0", + "web3-utils": "1.9.0" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-eth-ens": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.8.2.tgz", - "integrity": "sha512-PWph7C/CnqdWuu1+SH4U4zdrK4t2HNt0I4XzPYFdv9ugE8EuojselioPQXsVGvjql+Nt3jDLvQvggPqlMbvwRw==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.9.0.tgz", + "integrity": "sha512-LOJZeN+AGe9arhuExnrPPFYQr4WSxXEkpvYIlst/joOEUNLDwfndHnJIK6PI5mXaYSROBtTx6erv+HupzGo7vA==", "dev": true, "dependencies": { "content-hash": "^2.5.2", "eth-ens-namehash": "2.0.8", - "web3-core": "1.8.2", - "web3-core-helpers": "1.8.2", - "web3-core-promievent": "1.8.2", - "web3-eth-abi": "1.8.2", - "web3-eth-contract": "1.8.2", - "web3-utils": "1.8.2" + "web3-core": "1.9.0", + "web3-core-helpers": "1.9.0", + "web3-core-promievent": "1.9.0", + "web3-eth-abi": "1.9.0", + "web3-eth-contract": "1.9.0", + "web3-utils": "1.9.0" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-eth-iban": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.8.2.tgz", - "integrity": "sha512-h3vNblDWkWMuYx93Q27TAJz6lhzpP93EiC3+45D6xoz983p6si773vntoQ+H+5aZhwglBtoiBzdh7PSSOnP/xQ==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.9.0.tgz", + "integrity": "sha512-jPAm77PuEs1kE/UrrBFJdPD2PN42pwfXA0gFuuw35bZezhskYML9W4QCxcqnUtceyEA4FUn7K2qTMuCk+23fog==", "dev": true, "dependencies": { "bn.js": "^5.2.1", - "web3-utils": "1.8.2" + "web3-utils": "1.9.0" }, "engines": { "node": ">=8.0.0" @@ -14649,72 +15604,72 @@ "dev": true }, "node_modules/web3-eth-personal": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.8.2.tgz", - "integrity": "sha512-Vg4HfwCr7doiUF/RC+Jz0wT4+cYaXcOWMAW2AHIjHX6Z7Xwa8nrURIeQgeEE62qcEHAzajyAdB1u6bJyTfuCXw==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.9.0.tgz", + "integrity": "sha512-r9Ldo/luBqJlv1vCUEQnUS+C3a3ZdbYxVHyfDkj6RWMyCqqo8JE41HWE+pfa0RmB1xnGL2g8TbYcHcqItck/qg==", "dev": true, "dependencies": { "@types/node": "^12.12.6", - "web3-core": "1.8.2", - "web3-core-helpers": "1.8.2", - "web3-core-method": "1.8.2", - "web3-net": "1.8.2", - "web3-utils": "1.8.2" + "web3-core": "1.9.0", + "web3-core-helpers": "1.9.0", + "web3-core-method": "1.9.0", + "web3-net": "1.9.0", + "web3-utils": "1.9.0" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-net": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.8.2.tgz", - "integrity": "sha512-1itkDMGmbgb83Dg9nporFes9/fxsU7smJ3oRXlFkg4ZHn8YJyP1MSQFPJWWwSc+GrcCFt4O5IrUTvEkHqE3xag==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.9.0.tgz", + "integrity": "sha512-L+fDZFgrLM5Y15aonl2q6L+RvfaImAngmC0Jv45hV2FJ5IfRT0/2ob9etxZmvEBWvOpbqSvghfOhJIT3XZ37Pg==", "dev": true, "dependencies": { - "web3-core": "1.8.2", - "web3-core-method": "1.8.2", - "web3-utils": "1.8.2" + "web3-core": "1.9.0", + "web3-core-method": "1.9.0", + "web3-utils": "1.9.0" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-providers-http": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.8.2.tgz", - "integrity": "sha512-2xY94IIEQd16+b+vIBF4IC1p7GVaz9q4EUFscvMUjtEq4ru4Atdzjs9GP+jmcoo49p70II0UV3bqQcz0TQfVyQ==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.9.0.tgz", + "integrity": "sha512-5+dMNDAE0rRFz6SJpfnBqlVi2J5bB/Ivr2SanMt2YUrkxW5t8betZbzVwRkTbwtUvkqgj3xeUQzqpOttiv+IqQ==", "dev": true, "dependencies": { "abortcontroller-polyfill": "^1.7.3", "cross-fetch": "^3.1.4", "es6-promise": "^4.2.8", - "web3-core-helpers": "1.8.2" + "web3-core-helpers": "1.9.0" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-providers-ipc": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.8.2.tgz", - "integrity": "sha512-p6fqKVGFg+WiXGHWnB1hu43PbvPkDHTz4RgoEzbXugv5rtv5zfYLqm8Ba6lrJOS5ks9kGKR21a0y3NzE3u7V4w==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.9.0.tgz", + "integrity": "sha512-cPXU93Du40HCylvjaa5x62DbnGqH+86HpK/+kMcFIzF6sDUBhKpag2tSbYhGbj7GMpfkmDTUiiMLdWnFV6+uBA==", "dev": true, "dependencies": { "oboe": "2.1.5", - "web3-core-helpers": "1.8.2" + "web3-core-helpers": "1.9.0" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-providers-ws": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.8.2.tgz", - "integrity": "sha512-3s/4K+wHgbiN+Zrp9YjMq2eqAF6QGABw7wFftPdx+m5hWImV27/MoIx57c6HffNRqZXmCHnfWWFCNHHsi7wXnA==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.9.0.tgz", + "integrity": "sha512-JRVsnQZ7j2k1a2yzBNHe39xqk1ijOv01dfIBFw52VeEkSRzvrOcsPIM/ttSyBuJqt70ntMxXY0ekCrqfleKH/w==", "dev": true, "dependencies": { "eventemitter3": "4.0.4", - "web3-core-helpers": "1.8.2", + "web3-core-helpers": "1.9.0", "websocket": "^1.0.32" }, "engines": { @@ -14722,25 +15677,25 @@ } }, "node_modules/web3-shh": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.8.2.tgz", - "integrity": "sha512-uZ+3MAoNcaJsXXNCDnizKJ5viBNeHOFYsCbFhV755Uu52FswzTOw6DtE7yK9nYXMtIhiSgi7nwl1RYzP8pystw==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.9.0.tgz", + "integrity": "sha512-bIBZlralgz4ICCrwkefB2nPPJWfx28NuHIpjB7d9ADKynElubQuqudYhKtSEkKXACuME/BJm0pIFJcJs/gDnMg==", "dev": true, "hasInstallScript": true, "dependencies": { - "web3-core": "1.8.2", - "web3-core-method": "1.8.2", - "web3-core-subscriptions": "1.8.2", - "web3-net": "1.8.2" + "web3-core": "1.9.0", + "web3-core-method": "1.9.0", + "web3-core-subscriptions": "1.9.0", + "web3-net": "1.9.0" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-utils": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.8.2.tgz", - "integrity": "sha512-v7j6xhfLQfY7xQDrUP0BKbaNrmZ2/+egbqP9q3KYmOiPpnvAfol+32slgL0WX/5n8VPvKCK5EZ1HGrAVICSToA==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.9.0.tgz", + "integrity": "sha512-p++69rCNNfu2jM9n5+VD/g26l+qkEOQ1m6cfRQCbH8ZRrtquTmrirJMgTmyOoax5a5XRYOuws14aypCOs51pdQ==", "dev": true, "dependencies": { "bn.js": "^5.2.1", @@ -14841,9 +15796,9 @@ } }, "node_modules/which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", "dev": true }, "node_modules/which-pm": { @@ -15121,9 +16076,9 @@ "dev": true }, "node_modules/yargs": { - "version": "17.7.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", - "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, "dependencies": { "cliui": "^8.0.1", @@ -15276,9 +16231,9 @@ }, "dependencies": { "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", + "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", "dev": true, "requires": { "@babel/highlight": "^7.18.6" @@ -15302,14 +16257,40 @@ } }, "@babel/runtime": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", - "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.5.tgz", + "integrity": "sha512-8jI69toZqqcsnqGGqwGS4Qb1VwLOEp4hz+CXPywcvjs60u3B4Pom/U/7rm4W8tMOYEB+E9wgD0mW1l3r8qlI9Q==", "dev": true, "requires": { "regenerator-runtime": "^0.13.11" } }, + "@chainsafe/as-sha256": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@chainsafe/as-sha256/-/as-sha256-0.3.1.tgz", + "integrity": "sha512-hldFFYuf49ed7DAakWVXSJODuq3pzJEguD8tQ7h+sGkM18vja+OFoJI9krnGmgzyuZC2ETX0NOIcCTy31v2Mtg==", + "dev": true + }, + "@chainsafe/persistent-merkle-tree": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.4.2.tgz", + "integrity": "sha512-lLO3ihKPngXLTus/L7WHKaw9PnNJWizlOF1H9NNzHP6Xvh82vzg9F2bzkXhYIFshMZ2gTCEz8tq6STe7r5NDfQ==", + "dev": true, + "requires": { + "@chainsafe/as-sha256": "^0.3.1" + } + }, + "@chainsafe/ssz": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.9.4.tgz", + "integrity": "sha512-77Qtg2N1ayqs4Bg/wvnWfg5Bta7iy7IRh8XqXh7oNMeP2HBbBwx8m6yTpA8p0EHItWPEBkgZd5S5/LSlp3GXuQ==", + "dev": true, + "requires": { + "@chainsafe/as-sha256": "^0.3.1", + "@chainsafe/persistent-merkle-tree": "^0.4.2", + "case": "^1.6.3" + } + }, "@changesets/apply-release-plan": { "version": "6.1.3", "resolved": "https://registry.npmjs.org/@changesets/apply-release-plan/-/apply-release-plan-6.1.3.tgz", @@ -15382,9 +16363,9 @@ } }, "@changesets/cli": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/@changesets/cli/-/cli-2.26.0.tgz", - "integrity": "sha512-0cbTiDms+ICTVtEwAFLNW0jBNex9f5+fFv3I771nBvdnV/mOjd1QJ4+f8KtVSOrwD9SJkk9xbDkWFb0oXd8d1Q==", + "version": "2.26.1", + "resolved": "https://registry.npmjs.org/@changesets/cli/-/cli-2.26.1.tgz", + "integrity": "sha512-XnTa+b51vt057fyAudvDKGB0Sh72xutQZNAdXkCqPBKO2zvs2yYZx5hFZj1u9cbtpwM6Sxtcr02/FQJfZOzemQ==", "dev": true, "requires": { "@babel/runtime": "^7.20.1", @@ -15688,29 +16669,29 @@ "dev": true }, "@eslint-community/eslint-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.2.0.tgz", - "integrity": "sha512-gB8T4H4DEfX2IV9zGDJPOBgP1e/DbfCPDTtEqUMckpvzS1OYtva8JdFYBqMwYk7xAQ429WGF/UPqn8uQ//h2vQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", "dev": true, "requires": { "eslint-visitor-keys": "^3.3.0" } }, "@eslint-community/regexpp": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.4.0.tgz", - "integrity": "sha512-A9983Q0LnDGdLPjxyXQ00sbV+K+O+ko2Dr+CZigbHWtX9pNfxlaBkMR8X1CztI73zuEyEBXTVjx7CE+/VSwDiQ==", + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", + "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", "dev": true }, "@eslint/eslintrc": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.1.tgz", - "integrity": "sha512-eFRmABvW2E5Ho6f5fHLqgena46rOj7r7OKHYfLElqcBfGFHHpjBhivyi5+jOEQuSpdc/1phIZJlbC2te+tZNIw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", + "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.5.0", + "espree": "^9.5.1", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -15737,9 +16718,9 @@ } }, "@eslint/js": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.36.0.tgz", - "integrity": "sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.39.0.tgz", + "integrity": "sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==", "dev": true }, "@ethereumjs/common": { @@ -16361,31 +17342,73 @@ } }, "@nomicfoundation/ethereumjs-block": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-4.0.0.tgz", - "integrity": "sha512-bk8uP8VuexLgyIZAHExH1QEovqx0Lzhc9Ntm63nCRKLHXIZkobaFaeCVwTESV7YkPKUk7NiK11s8ryed4CS9yA==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-5.0.1.tgz", + "integrity": "sha512-u1Yioemi6Ckj3xspygu/SfFvm8vZEO8/Yx5a1QLzi6nVU0jz3Pg2OmHKJ5w+D9Ogk1vhwRiqEBAqcb0GVhCyHw==", "dev": true, "requires": { - "@nomicfoundation/ethereumjs-common": "^3.0.0", - "@nomicfoundation/ethereumjs-rlp": "^4.0.0", - "@nomicfoundation/ethereumjs-trie": "^5.0.0", - "@nomicfoundation/ethereumjs-tx": "^4.0.0", - "@nomicfoundation/ethereumjs-util": "^8.0.0", - "ethereum-cryptography": "0.1.3" + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-trie": "6.0.1", + "@nomicfoundation/ethereumjs-tx": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "ethereum-cryptography": "0.1.3", + "ethers": "^5.7.1" + }, + "dependencies": { + "ethers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz", + "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", + "dev": true, + "requires": { + "@ethersproject/abi": "5.7.0", + "@ethersproject/abstract-provider": "5.7.0", + "@ethersproject/abstract-signer": "5.7.0", + "@ethersproject/address": "5.7.0", + "@ethersproject/base64": "5.7.0", + "@ethersproject/basex": "5.7.0", + "@ethersproject/bignumber": "5.7.0", + "@ethersproject/bytes": "5.7.0", + "@ethersproject/constants": "5.7.0", + "@ethersproject/contracts": "5.7.0", + "@ethersproject/hash": "5.7.0", + "@ethersproject/hdnode": "5.7.0", + "@ethersproject/json-wallets": "5.7.0", + "@ethersproject/keccak256": "5.7.0", + "@ethersproject/logger": "5.7.0", + "@ethersproject/networks": "5.7.1", + "@ethersproject/pbkdf2": "5.7.0", + "@ethersproject/properties": "5.7.0", + "@ethersproject/providers": "5.7.2", + "@ethersproject/random": "5.7.0", + "@ethersproject/rlp": "5.7.0", + "@ethersproject/sha2": "5.7.0", + "@ethersproject/signing-key": "5.7.0", + "@ethersproject/solidity": "5.7.0", + "@ethersproject/strings": "5.7.0", + "@ethersproject/transactions": "5.7.0", + "@ethersproject/units": "5.7.0", + "@ethersproject/wallet": "5.7.0", + "@ethersproject/web": "5.7.1", + "@ethersproject/wordlists": "5.7.0" + } + } } }, "@nomicfoundation/ethereumjs-blockchain": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-blockchain/-/ethereumjs-blockchain-6.0.0.tgz", - "integrity": "sha512-pLFEoea6MWd81QQYSReLlLfH7N9v7lH66JC/NMPN848ySPPQA5renWnE7wPByfQFzNrPBuDDRFFULMDmj1C0xw==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-blockchain/-/ethereumjs-blockchain-7.0.1.tgz", + "integrity": "sha512-NhzndlGg829XXbqJEYrF1VeZhAwSPgsK/OB7TVrdzft3y918hW5KNd7gIZ85sn6peDZOdjBsAXIpXZ38oBYE5A==", "dev": true, "requires": { - "@nomicfoundation/ethereumjs-block": "^4.0.0", - "@nomicfoundation/ethereumjs-common": "^3.0.0", - "@nomicfoundation/ethereumjs-ethash": "^2.0.0", - "@nomicfoundation/ethereumjs-rlp": "^4.0.0", - "@nomicfoundation/ethereumjs-trie": "^5.0.0", - "@nomicfoundation/ethereumjs-util": "^8.0.0", + "@nomicfoundation/ethereumjs-block": "5.0.1", + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-ethash": "3.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-trie": "6.0.1", + "@nomicfoundation/ethereumjs-tx": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", "abstract-level": "^1.0.3", "debug": "^4.3.3", "ethereum-cryptography": "0.1.3", @@ -16395,39 +17418,39 @@ } }, "@nomicfoundation/ethereumjs-common": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-3.0.0.tgz", - "integrity": "sha512-WS7qSshQfxoZOpHG/XqlHEGRG1zmyjYrvmATvc4c62+gZXgre1ymYP8ZNgx/3FyZY0TWe9OjFlKOfLqmgOeYwA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.1.tgz", + "integrity": "sha512-OBErlkfp54GpeiE06brBW/TTbtbuBJV5YI5Nz/aB2evTDo+KawyEzPjBlSr84z/8MFfj8wS2wxzQX1o32cev5g==", "dev": true, "requires": { - "@nomicfoundation/ethereumjs-util": "^8.0.0", + "@nomicfoundation/ethereumjs-util": "9.0.1", "crc-32": "^1.2.0" } }, "@nomicfoundation/ethereumjs-ethash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-ethash/-/ethereumjs-ethash-2.0.0.tgz", - "integrity": "sha512-WpDvnRncfDUuXdsAXlI4lXbqUDOA+adYRQaEezIkxqDkc+LDyYDbd/xairmY98GnQzo1zIqsIL6GB5MoMSJDew==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-ethash/-/ethereumjs-ethash-3.0.1.tgz", + "integrity": "sha512-KDjGIB5igzWOp8Ik5I6QiRH5DH+XgILlplsHR7TEuWANZA759G6krQ6o8bvj+tRUz08YygMQu/sGd9mJ1DYT8w==", "dev": true, "requires": { - "@nomicfoundation/ethereumjs-block": "^4.0.0", - "@nomicfoundation/ethereumjs-rlp": "^4.0.0", - "@nomicfoundation/ethereumjs-util": "^8.0.0", + "@nomicfoundation/ethereumjs-block": "5.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", "abstract-level": "^1.0.3", "bigint-crypto-utils": "^3.0.23", "ethereum-cryptography": "0.1.3" } }, "@nomicfoundation/ethereumjs-evm": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-evm/-/ethereumjs-evm-1.0.0.tgz", - "integrity": "sha512-hVS6qRo3V1PLKCO210UfcEQHvlG7GqR8iFzp0yyjTg2TmJQizcChKgWo8KFsdMw6AyoLgLhHGHw4HdlP8a4i+Q==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-evm/-/ethereumjs-evm-2.0.1.tgz", + "integrity": "sha512-oL8vJcnk0Bx/onl+TgQOQ1t/534GKFaEG17fZmwtPFeH8S5soiBYPCLUrvANOl4sCp9elYxIMzIiTtMtNNN8EQ==", "dev": true, "requires": { - "@nomicfoundation/ethereumjs-common": "^3.0.0", - "@nomicfoundation/ethereumjs-util": "^8.0.0", - "@types/async-eventemitter": "^0.2.1", - "async-eventemitter": "^0.2.4", + "@ethersproject/providers": "^5.7.1", + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-tx": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", "debug": "^4.3.3", "ethereum-cryptography": "0.1.3", "mcl-wasm": "^0.7.1", @@ -16435,80 +17458,141 @@ } }, "@nomicfoundation/ethereumjs-rlp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-4.0.0.tgz", - "integrity": "sha512-GaSOGk5QbUk4eBP5qFbpXoZoZUj/NrW7MRa0tKY4Ew4c2HAS0GXArEMAamtFrkazp0BO4K5p2ZCG3b2FmbShmw==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.1.tgz", + "integrity": "sha512-xtxrMGa8kP4zF5ApBQBtjlSbN5E2HI8m8FYgVSYAnO6ssUoY5pVPGy2H8+xdf/bmMa22Ce8nWMH3aEW8CcqMeQ==", "dev": true }, "@nomicfoundation/ethereumjs-statemanager": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-statemanager/-/ethereumjs-statemanager-1.0.0.tgz", - "integrity": "sha512-jCtqFjcd2QejtuAMjQzbil/4NHf5aAWxUc+CvS0JclQpl+7M0bxMofR2AJdtz+P3u0ke2euhYREDiE7iSO31vQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-statemanager/-/ethereumjs-statemanager-2.0.1.tgz", + "integrity": "sha512-B5ApMOnlruVOR7gisBaYwFX+L/AP7i/2oAahatssjPIBVDF6wTX1K7Qpa39E/nzsH8iYuL3krkYeUFIdO3EMUQ==", "dev": true, "requires": { - "@nomicfoundation/ethereumjs-common": "^3.0.0", - "@nomicfoundation/ethereumjs-rlp": "^4.0.0", - "@nomicfoundation/ethereumjs-trie": "^5.0.0", - "@nomicfoundation/ethereumjs-util": "^8.0.0", + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", "debug": "^4.3.3", "ethereum-cryptography": "0.1.3", - "functional-red-black-tree": "^1.0.1" + "ethers": "^5.7.1", + "js-sdsl": "^4.1.4" + }, + "dependencies": { + "ethers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz", + "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", + "dev": true, + "requires": { + "@ethersproject/abi": "5.7.0", + "@ethersproject/abstract-provider": "5.7.0", + "@ethersproject/abstract-signer": "5.7.0", + "@ethersproject/address": "5.7.0", + "@ethersproject/base64": "5.7.0", + "@ethersproject/basex": "5.7.0", + "@ethersproject/bignumber": "5.7.0", + "@ethersproject/bytes": "5.7.0", + "@ethersproject/constants": "5.7.0", + "@ethersproject/contracts": "5.7.0", + "@ethersproject/hash": "5.7.0", + "@ethersproject/hdnode": "5.7.0", + "@ethersproject/json-wallets": "5.7.0", + "@ethersproject/keccak256": "5.7.0", + "@ethersproject/logger": "5.7.0", + "@ethersproject/networks": "5.7.1", + "@ethersproject/pbkdf2": "5.7.0", + "@ethersproject/properties": "5.7.0", + "@ethersproject/providers": "5.7.2", + "@ethersproject/random": "5.7.0", + "@ethersproject/rlp": "5.7.0", + "@ethersproject/sha2": "5.7.0", + "@ethersproject/signing-key": "5.7.0", + "@ethersproject/solidity": "5.7.0", + "@ethersproject/strings": "5.7.0", + "@ethersproject/transactions": "5.7.0", + "@ethersproject/units": "5.7.0", + "@ethersproject/wallet": "5.7.0", + "@ethersproject/web": "5.7.1", + "@ethersproject/wordlists": "5.7.0" + } + } } }, "@nomicfoundation/ethereumjs-trie": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-trie/-/ethereumjs-trie-5.0.0.tgz", - "integrity": "sha512-LIj5XdE+s+t6WSuq/ttegJzZ1vliwg6wlb+Y9f4RlBpuK35B9K02bO7xU+E6Rgg9RGptkWd6TVLdedTI4eNc2A==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-trie/-/ethereumjs-trie-6.0.1.tgz", + "integrity": "sha512-A64It/IMpDVODzCgxDgAAla8jNjNtsoQZIzZUfIV5AY6Coi4nvn7+VReBn5itlxMiL2yaTlQr9TRWp3CSI6VoA==", "dev": true, "requires": { - "@nomicfoundation/ethereumjs-rlp": "^4.0.0", - "@nomicfoundation/ethereumjs-util": "^8.0.0", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "@types/readable-stream": "^2.3.13", "ethereum-cryptography": "0.1.3", "readable-stream": "^3.6.0" } }, "@nomicfoundation/ethereumjs-tx": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-4.0.0.tgz", - "integrity": "sha512-Gg3Lir2lNUck43Kp/3x6TfBNwcWC9Z1wYue9Nz3v4xjdcv6oDW9QSMJxqsKw9QEGoBBZ+gqwpW7+F05/rs/g1w==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.1.tgz", + "integrity": "sha512-0HwxUF2u2hrsIM1fsasjXvlbDOq1ZHFV2dd1yGq8CA+MEYhaxZr8OTScpVkkxqMwBcc5y83FyPl0J9MZn3kY0w==", "dev": true, "requires": { - "@nomicfoundation/ethereumjs-common": "^3.0.0", - "@nomicfoundation/ethereumjs-rlp": "^4.0.0", - "@nomicfoundation/ethereumjs-util": "^8.0.0", + "@chainsafe/ssz": "^0.9.2", + "@ethersproject/providers": "^5.7.2", + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", "ethereum-cryptography": "0.1.3" } }, "@nomicfoundation/ethereumjs-util": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-8.0.0.tgz", - "integrity": "sha512-2emi0NJ/HmTG+CGY58fa+DQuAoroFeSH9gKu9O6JnwTtlzJtgfTixuoOqLEgyyzZVvwfIpRueuePb8TonL1y+A==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.1.tgz", + "integrity": "sha512-TwbhOWQ8QoSCFhV/DDfSmyfFIHjPjFBj957219+V3jTZYZ2rf9PmDtNOeZWAE3p3vlp8xb02XGpd0v6nTUPbsA==", "dev": true, "requires": { - "@nomicfoundation/ethereumjs-rlp": "^4.0.0-beta.2", + "@chainsafe/ssz": "^0.10.0", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", "ethereum-cryptography": "0.1.3" + }, + "dependencies": { + "@chainsafe/persistent-merkle-tree": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.5.0.tgz", + "integrity": "sha512-l0V1b5clxA3iwQLXP40zYjyZYospQLZXzBVIhhr9kDg/1qHZfzzHw0jj4VPBijfYCArZDlPkRi1wZaV2POKeuw==", + "dev": true, + "requires": { + "@chainsafe/as-sha256": "^0.3.1" + } + }, + "@chainsafe/ssz": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.10.2.tgz", + "integrity": "sha512-/NL3Lh8K+0q7A3LsiFq09YXS9fPE+ead2rr7vM2QK8PLzrNsw3uqrif9bpRX5UxgeRjM+vYi+boCM3+GM4ovXg==", + "dev": true, + "requires": { + "@chainsafe/as-sha256": "^0.3.1", + "@chainsafe/persistent-merkle-tree": "^0.5.0" + } + } } }, "@nomicfoundation/ethereumjs-vm": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-vm/-/ethereumjs-vm-6.0.0.tgz", - "integrity": "sha512-JMPxvPQ3fzD063Sg3Tp+UdwUkVxMoo1uML6KSzFhMH3hoQi/LMuXBoEHAoW83/vyNS9BxEe6jm6LmT5xdeEJ6w==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-vm/-/ethereumjs-vm-7.0.1.tgz", + "integrity": "sha512-rArhyn0jPsS/D+ApFsz3yVJMQ29+pVzNZ0VJgkzAZ+7FqXSRtThl1C1prhmlVr3YNUlfpZ69Ak+RUT4g7VoOuQ==", "dev": true, "requires": { - "@nomicfoundation/ethereumjs-block": "^4.0.0", - "@nomicfoundation/ethereumjs-blockchain": "^6.0.0", - "@nomicfoundation/ethereumjs-common": "^3.0.0", - "@nomicfoundation/ethereumjs-evm": "^1.0.0", - "@nomicfoundation/ethereumjs-rlp": "^4.0.0", - "@nomicfoundation/ethereumjs-statemanager": "^1.0.0", - "@nomicfoundation/ethereumjs-trie": "^5.0.0", - "@nomicfoundation/ethereumjs-tx": "^4.0.0", - "@nomicfoundation/ethereumjs-util": "^8.0.0", - "@types/async-eventemitter": "^0.2.1", - "async-eventemitter": "^0.2.4", + "@nomicfoundation/ethereumjs-block": "5.0.1", + "@nomicfoundation/ethereumjs-blockchain": "7.0.1", + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-evm": "2.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-statemanager": "2.0.1", + "@nomicfoundation/ethereumjs-trie": "6.0.1", + "@nomicfoundation/ethereumjs-tx": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", "debug": "^4.3.3", "ethereum-cryptography": "0.1.3", - "functional-red-black-tree": "^1.0.1", "mcl-wasm": "^0.7.1", "rustbn.js": "~0.2.0" } @@ -16774,9 +17858,9 @@ } }, "@openzeppelin/upgrades-core": { - "version": "1.24.1", - "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades-core/-/upgrades-core-1.24.1.tgz", - "integrity": "sha512-QhdIQDUykJ3vQauB6CheV7vk4zgn0e1iY+IDg7r1KqpA1m2bqIGjQCpzidW33K4bZc9zdJSPx2/Z6Um5KxCB7A==", + "version": "1.25.0", + "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades-core/-/upgrades-core-1.25.0.tgz", + "integrity": "sha512-vSxOSm1k+P156nNm15ydhOmSPGC37mnl092FMVOH+eGaoqLjr2Za6ULVjDMFzvMnG+sGE1UoDOqBNPfTm0ch8w==", "dev": true, "requires": { "cbor": "^8.0.0", @@ -16980,18 +18064,41 @@ "change-case": "3.0.2", "fast-check": "3.1.1", "web3-utils": "1.8.2" + }, + "dependencies": { + "bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "dev": true + }, + "web3-utils": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.8.2.tgz", + "integrity": "sha512-v7j6xhfLQfY7xQDrUP0BKbaNrmZ2/+egbqP9q3KYmOiPpnvAfol+32slgL0WX/5n8VPvKCK5EZ1HGrAVICSToA==", + "dev": true, + "requires": { + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereumjs-util": "^7.1.0", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + } + } } }, "@truffle/blockchain-utils": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@truffle/blockchain-utils/-/blockchain-utils-0.1.6.tgz", - "integrity": "sha512-SldoNRIFSm3+HMBnSc2jFsu5TWDkCN4X6vL3wrd0t6DIeF7nD6EoPPjxwbFSoqCnkkRxMuZeL6sUx7UMJS/wSA==", + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/@truffle/blockchain-utils/-/blockchain-utils-0.1.7.tgz", + "integrity": "sha512-1nibqGjEHC7KAyDThEFvbm2+EO8zAHee/VjCtxkYBE3ySwP50joh0QCEBjy7K/9z+icpMoDucfxmgaKToBFUgQ==", "dev": true }, "@truffle/codec": { - "version": "0.14.16", - "resolved": "https://registry.npmjs.org/@truffle/codec/-/codec-0.14.16.tgz", - "integrity": "sha512-a9UY3n/FnkKN3Q4zOuMFOOcLWb80mdknj+voim4vvXYtJm1aAZQZE5sG9aLnMBTl4TiGLzUtfNDVYY7WgWgDag==", + "version": "0.14.17", + "resolved": "https://registry.npmjs.org/@truffle/codec/-/codec-0.14.17.tgz", + "integrity": "sha512-kD4dD86huLeaBEq5R8D1zleJEu6NsXbyYLdXl1V1TKdiO8odw5CBC6Y/+wdu5d3t1dyEYrTbhn1dqknZa52pmw==", "dev": true, "requires": { "@truffle/abi-utils": "^0.3.9", @@ -17052,6 +18159,21 @@ "lru-cache": "^6.0.0" } }, + "web3-utils": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.8.2.tgz", + "integrity": "sha512-v7j6xhfLQfY7xQDrUP0BKbaNrmZ2/+egbqP9q3KYmOiPpnvAfol+32slgL0WX/5n8VPvKCK5EZ1HGrAVICSToA==", + "dev": true, + "requires": { + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereumjs-util": "^7.1.0", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + } + }, "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -17079,17 +18201,17 @@ } }, "@truffle/contract": { - "version": "4.6.17", - "resolved": "https://registry.npmjs.org/@truffle/contract/-/contract-4.6.17.tgz", - "integrity": "sha512-sIMam5Wqr9AEiqHfOcWGJGqTv8Qy+BT765PaNHUUT6JBAY+tpHM3FlQd2nM6zLJ8paR3SLDGIthkhCBH/KNgDA==", + "version": "4.6.20", + "resolved": "https://registry.npmjs.org/@truffle/contract/-/contract-4.6.20.tgz", + "integrity": "sha512-s7Mbc37L/CF5Apy/cjPnalkgACmG9tTAmcIW28cIZLRLOUAze18pqhtdHryxAQhEOtKGaDAho6TriqL7/74uHw==", "dev": true, "requires": { "@ensdomains/ensjs": "^2.1.0", - "@truffle/blockchain-utils": "^0.1.6", + "@truffle/blockchain-utils": "^0.1.7", "@truffle/contract-schema": "^3.4.13", - "@truffle/debug-utils": "^6.0.47", + "@truffle/debug-utils": "^6.0.48", "@truffle/error": "^0.2.0", - "@truffle/interface-adapter": "^0.5.30", + "@truffle/interface-adapter": "^0.5.32", "bignumber.js": "^7.2.1", "debug": "^4.3.1", "ethers": "^4.0.32", @@ -17105,6 +18227,318 @@ "resolved": "https://registry.npmjs.org/@truffle/error/-/error-0.2.0.tgz", "integrity": "sha512-Fe0/z4WWb7IP2gBnv3l6zqP87Y0kSMs7oiSLakKJq17q3GUunrHSdioKuNspdggxkXIBhEQLhi8C+LJdwmHKWQ==", "dev": true + }, + "eth-lib": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.8.tgz", + "integrity": "sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw==", + "dev": true, + "requires": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "xhr-request-promise": "^0.1.2" + } + }, + "uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "dev": true + }, + "web3": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.8.2.tgz", + "integrity": "sha512-92h0GdEHW9wqDICQQKyG4foZBYi0OQkyg4CRml2F7XBl/NG+fu9o6J19kzfFXzSBoA4DnJXbyRgj/RHZv5LRiw==", + "dev": true, + "requires": { + "web3-bzz": "1.8.2", + "web3-core": "1.8.2", + "web3-eth": "1.8.2", + "web3-eth-personal": "1.8.2", + "web3-net": "1.8.2", + "web3-shh": "1.8.2", + "web3-utils": "1.8.2" + } + }, + "web3-bzz": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.8.2.tgz", + "integrity": "sha512-1EEnxjPnFnvNWw3XeeKuTR8PBxYd0+XWzvaLK7OJC/Go9O8llLGxrxICbKV+8cgIE0sDRBxiYx02X+6OhoAQ9w==", + "dev": true, + "requires": { + "@types/node": "^12.12.6", + "got": "12.1.0", + "swarm-js": "^0.1.40" + } + }, + "web3-core": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.8.2.tgz", + "integrity": "sha512-DJTVEAYcNqxkqruJE+Rxp3CIv0y5AZMwPHQmOkz/cz+MM75SIzMTc0AUdXzGyTS8xMF8h3YWMQGgGEy8SBf1PQ==", + "dev": true, + "requires": { + "@types/bn.js": "^5.1.0", + "@types/node": "^12.12.6", + "bignumber.js": "^9.0.0", + "web3-core-helpers": "1.8.2", + "web3-core-method": "1.8.2", + "web3-core-requestmanager": "1.8.2", + "web3-utils": "1.8.2" + }, + "dependencies": { + "bignumber.js": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz", + "integrity": "sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig==", + "dev": true + } + } + }, + "web3-core-helpers": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.8.2.tgz", + "integrity": "sha512-6B1eLlq9JFrfealZBomd1fmlq1o4A09vrCVQSa51ANoib/jllT3atZrRDr0zt1rfI7TSZTZBXdN/aTdeN99DWw==", + "dev": true, + "requires": { + "web3-eth-iban": "1.8.2", + "web3-utils": "1.8.2" + } + }, + "web3-core-method": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.8.2.tgz", + "integrity": "sha512-1qnr5mw5wVyULzLOrk4B+ryO3gfGjGd/fx8NR+J2xCGLf1e6OSjxT9vbfuQ3fErk/NjSTWWreieYWLMhaogcRA==", + "dev": true, + "requires": { + "@ethersproject/transactions": "^5.6.2", + "web3-core-helpers": "1.8.2", + "web3-core-promievent": "1.8.2", + "web3-core-subscriptions": "1.8.2", + "web3-utils": "1.8.2" + } + }, + "web3-core-promievent": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.8.2.tgz", + "integrity": "sha512-nvkJWDVgoOSsolJldN33tKW6bKKRJX3MCPDYMwP5SUFOA/mCzDEoI88N0JFofDTXkh1k7gOqp1pvwi9heuaxGg==", + "dev": true, + "requires": { + "eventemitter3": "4.0.4" + } + }, + "web3-core-requestmanager": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.8.2.tgz", + "integrity": "sha512-p1d090RYs5Mu7DK1yyc3GCBVZB/03rBtFhYFoS2EruGzOWs/5Q0grgtpwS/DScdRAm8wB8mYEBhY/RKJWF6B2g==", + "dev": true, + "requires": { + "util": "^0.12.5", + "web3-core-helpers": "1.8.2", + "web3-providers-http": "1.8.2", + "web3-providers-ipc": "1.8.2", + "web3-providers-ws": "1.8.2" + } + }, + "web3-core-subscriptions": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.8.2.tgz", + "integrity": "sha512-vXQogHDmAIQcKpXvGiMddBUeP9lnKgYF64+yQJhPNE5PnWr1sAibXuIPV7mIPihpFr/n/DORRj6Wh1pUv9zaTw==", + "dev": true, + "requires": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.8.2" + } + }, + "web3-eth": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.8.2.tgz", + "integrity": "sha512-JoTiWWc4F4TInpbvDUGb0WgDYJsFhuIjJlinc5ByjWD88Gvh+GKLsRjjFdbqe5YtwIGT4NymwoC5LQd1K6u/QQ==", + "dev": true, + "requires": { + "web3-core": "1.8.2", + "web3-core-helpers": "1.8.2", + "web3-core-method": "1.8.2", + "web3-core-subscriptions": "1.8.2", + "web3-eth-abi": "1.8.2", + "web3-eth-accounts": "1.8.2", + "web3-eth-contract": "1.8.2", + "web3-eth-ens": "1.8.2", + "web3-eth-iban": "1.8.2", + "web3-eth-personal": "1.8.2", + "web3-net": "1.8.2", + "web3-utils": "1.8.2" + } + }, + "web3-eth-abi": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.8.2.tgz", + "integrity": "sha512-Om9g3kaRNjqiNPAgKwGT16y+ZwtBzRe4ZJFGjLiSs6v5I7TPNF+rRMWuKnR6jq0azQZDj6rblvKFMA49/k48Og==", + "dev": true, + "requires": { + "@ethersproject/abi": "^5.6.3", + "web3-utils": "1.8.2" + } + }, + "web3-eth-accounts": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.8.2.tgz", + "integrity": "sha512-c367Ij63VCz9YdyjiHHWLFtN85l6QghgwMQH2B1eM/p9Y5lTlTX7t/Eg/8+f1yoIStXbk2w/PYM2lk+IkbqdLA==", + "dev": true, + "requires": { + "@ethereumjs/common": "2.5.0", + "@ethereumjs/tx": "3.3.2", + "eth-lib": "0.2.8", + "ethereumjs-util": "^7.1.5", + "scrypt-js": "^3.0.1", + "uuid": "^9.0.0", + "web3-core": "1.8.2", + "web3-core-helpers": "1.8.2", + "web3-core-method": "1.8.2", + "web3-utils": "1.8.2" + } + }, + "web3-eth-contract": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.8.2.tgz", + "integrity": "sha512-ID5A25tHTSBNwOPjiXSVzxruz006ULRIDbzWTYIFTp7NJ7vXu/kynKK2ag/ObuTqBpMbobP8nXcA9b5EDkIdQA==", + "dev": true, + "requires": { + "@types/bn.js": "^5.1.0", + "web3-core": "1.8.2", + "web3-core-helpers": "1.8.2", + "web3-core-method": "1.8.2", + "web3-core-promievent": "1.8.2", + "web3-core-subscriptions": "1.8.2", + "web3-eth-abi": "1.8.2", + "web3-utils": "1.8.2" + } + }, + "web3-eth-ens": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.8.2.tgz", + "integrity": "sha512-PWph7C/CnqdWuu1+SH4U4zdrK4t2HNt0I4XzPYFdv9ugE8EuojselioPQXsVGvjql+Nt3jDLvQvggPqlMbvwRw==", + "dev": true, + "requires": { + "content-hash": "^2.5.2", + "eth-ens-namehash": "2.0.8", + "web3-core": "1.8.2", + "web3-core-helpers": "1.8.2", + "web3-core-promievent": "1.8.2", + "web3-eth-abi": "1.8.2", + "web3-eth-contract": "1.8.2", + "web3-utils": "1.8.2" + } + }, + "web3-eth-iban": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.8.2.tgz", + "integrity": "sha512-h3vNblDWkWMuYx93Q27TAJz6lhzpP93EiC3+45D6xoz983p6si773vntoQ+H+5aZhwglBtoiBzdh7PSSOnP/xQ==", + "dev": true, + "requires": { + "bn.js": "^5.2.1", + "web3-utils": "1.8.2" + }, + "dependencies": { + "bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "dev": true + } + } + }, + "web3-eth-personal": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.8.2.tgz", + "integrity": "sha512-Vg4HfwCr7doiUF/RC+Jz0wT4+cYaXcOWMAW2AHIjHX6Z7Xwa8nrURIeQgeEE62qcEHAzajyAdB1u6bJyTfuCXw==", + "dev": true, + "requires": { + "@types/node": "^12.12.6", + "web3-core": "1.8.2", + "web3-core-helpers": "1.8.2", + "web3-core-method": "1.8.2", + "web3-net": "1.8.2", + "web3-utils": "1.8.2" + } + }, + "web3-net": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.8.2.tgz", + "integrity": "sha512-1itkDMGmbgb83Dg9nporFes9/fxsU7smJ3oRXlFkg4ZHn8YJyP1MSQFPJWWwSc+GrcCFt4O5IrUTvEkHqE3xag==", + "dev": true, + "requires": { + "web3-core": "1.8.2", + "web3-core-method": "1.8.2", + "web3-utils": "1.8.2" + } + }, + "web3-providers-http": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.8.2.tgz", + "integrity": "sha512-2xY94IIEQd16+b+vIBF4IC1p7GVaz9q4EUFscvMUjtEq4ru4Atdzjs9GP+jmcoo49p70II0UV3bqQcz0TQfVyQ==", + "dev": true, + "requires": { + "abortcontroller-polyfill": "^1.7.3", + "cross-fetch": "^3.1.4", + "es6-promise": "^4.2.8", + "web3-core-helpers": "1.8.2" + } + }, + "web3-providers-ipc": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.8.2.tgz", + "integrity": "sha512-p6fqKVGFg+WiXGHWnB1hu43PbvPkDHTz4RgoEzbXugv5rtv5zfYLqm8Ba6lrJOS5ks9kGKR21a0y3NzE3u7V4w==", + "dev": true, + "requires": { + "oboe": "2.1.5", + "web3-core-helpers": "1.8.2" + } + }, + "web3-providers-ws": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.8.2.tgz", + "integrity": "sha512-3s/4K+wHgbiN+Zrp9YjMq2eqAF6QGABw7wFftPdx+m5hWImV27/MoIx57c6HffNRqZXmCHnfWWFCNHHsi7wXnA==", + "dev": true, + "requires": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.8.2", + "websocket": "^1.0.32" + } + }, + "web3-shh": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.8.2.tgz", + "integrity": "sha512-uZ+3MAoNcaJsXXNCDnizKJ5viBNeHOFYsCbFhV755Uu52FswzTOw6DtE7yK9nYXMtIhiSgi7nwl1RYzP8pystw==", + "dev": true, + "requires": { + "web3-core": "1.8.2", + "web3-core-method": "1.8.2", + "web3-core-subscriptions": "1.8.2", + "web3-net": "1.8.2" + } + }, + "web3-utils": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.8.2.tgz", + "integrity": "sha512-v7j6xhfLQfY7xQDrUP0BKbaNrmZ2/+egbqP9q3KYmOiPpnvAfol+32slgL0WX/5n8VPvKCK5EZ1HGrAVICSToA==", + "dev": true, + "requires": { + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereumjs-util": "^7.1.0", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + }, + "dependencies": { + "bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "dev": true + } + } } } }, @@ -17119,12 +18553,12 @@ } }, "@truffle/debug-utils": { - "version": "6.0.47", - "resolved": "https://registry.npmjs.org/@truffle/debug-utils/-/debug-utils-6.0.47.tgz", - "integrity": "sha512-bUjdzLPdEKtoUCDzaXkrOoi+PbyAJlMBzGequBK8tirT7xL9bCP2Pd/WxvnmRd7AnfroxGNvXwVXWTItW5SMWQ==", + "version": "6.0.48", + "resolved": "https://registry.npmjs.org/@truffle/debug-utils/-/debug-utils-6.0.48.tgz", + "integrity": "sha512-HdK/7eH5EFrcTPeZVEgKaKkkzuZ4xsrH8yw+EoLEsScLsOEuQeKynY61NctjuU93voATWrYmV99Sfb/MRq2i2g==", "dev": true, "requires": { - "@truffle/codec": "^0.14.16", + "@truffle/codec": "^0.14.17", "@trufflesuite/chromafi": "^3.0.0", "bn.js": "^5.1.3", "chalk": "^2.4.2", @@ -17147,9 +18581,9 @@ "dev": true }, "@truffle/interface-adapter": { - "version": "0.5.30", - "resolved": "https://registry.npmjs.org/@truffle/interface-adapter/-/interface-adapter-0.5.30.tgz", - "integrity": "sha512-wyCcESeZJBkAfuSGU8GHCusIWDUDyQjJZMcyShv59ZTSAwQR7xx0+a0Q1LlS532G/pGFLYe2VzKSY1pRHRwgug==", + "version": "0.5.32", + "resolved": "https://registry.npmjs.org/@truffle/interface-adapter/-/interface-adapter-0.5.32.tgz", + "integrity": "sha512-7Hgmdb4nJUcWtq4vvgWY7Mr2RLOTOp5FZaWyMiFmjkcEEhDlezm2QstALWAXgT0W6q7tDmDBpw3vTIFenRhHBA==", "dev": true, "requires": { "bn.js": "^5.1.3", @@ -17157,11 +18591,313 @@ "web3": "1.8.2" }, "dependencies": { + "bignumber.js": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz", + "integrity": "sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig==", + "dev": true + }, "bn.js": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", "dev": true + }, + "eth-lib": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.8.tgz", + "integrity": "sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw==", + "dev": true, + "requires": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "xhr-request-promise": "^0.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "dev": true + }, + "web3": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.8.2.tgz", + "integrity": "sha512-92h0GdEHW9wqDICQQKyG4foZBYi0OQkyg4CRml2F7XBl/NG+fu9o6J19kzfFXzSBoA4DnJXbyRgj/RHZv5LRiw==", + "dev": true, + "requires": { + "web3-bzz": "1.8.2", + "web3-core": "1.8.2", + "web3-eth": "1.8.2", + "web3-eth-personal": "1.8.2", + "web3-net": "1.8.2", + "web3-shh": "1.8.2", + "web3-utils": "1.8.2" + } + }, + "web3-bzz": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.8.2.tgz", + "integrity": "sha512-1EEnxjPnFnvNWw3XeeKuTR8PBxYd0+XWzvaLK7OJC/Go9O8llLGxrxICbKV+8cgIE0sDRBxiYx02X+6OhoAQ9w==", + "dev": true, + "requires": { + "@types/node": "^12.12.6", + "got": "12.1.0", + "swarm-js": "^0.1.40" + } + }, + "web3-core": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.8.2.tgz", + "integrity": "sha512-DJTVEAYcNqxkqruJE+Rxp3CIv0y5AZMwPHQmOkz/cz+MM75SIzMTc0AUdXzGyTS8xMF8h3YWMQGgGEy8SBf1PQ==", + "dev": true, + "requires": { + "@types/bn.js": "^5.1.0", + "@types/node": "^12.12.6", + "bignumber.js": "^9.0.0", + "web3-core-helpers": "1.8.2", + "web3-core-method": "1.8.2", + "web3-core-requestmanager": "1.8.2", + "web3-utils": "1.8.2" + } + }, + "web3-core-helpers": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.8.2.tgz", + "integrity": "sha512-6B1eLlq9JFrfealZBomd1fmlq1o4A09vrCVQSa51ANoib/jllT3atZrRDr0zt1rfI7TSZTZBXdN/aTdeN99DWw==", + "dev": true, + "requires": { + "web3-eth-iban": "1.8.2", + "web3-utils": "1.8.2" + } + }, + "web3-core-method": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.8.2.tgz", + "integrity": "sha512-1qnr5mw5wVyULzLOrk4B+ryO3gfGjGd/fx8NR+J2xCGLf1e6OSjxT9vbfuQ3fErk/NjSTWWreieYWLMhaogcRA==", + "dev": true, + "requires": { + "@ethersproject/transactions": "^5.6.2", + "web3-core-helpers": "1.8.2", + "web3-core-promievent": "1.8.2", + "web3-core-subscriptions": "1.8.2", + "web3-utils": "1.8.2" + } + }, + "web3-core-promievent": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.8.2.tgz", + "integrity": "sha512-nvkJWDVgoOSsolJldN33tKW6bKKRJX3MCPDYMwP5SUFOA/mCzDEoI88N0JFofDTXkh1k7gOqp1pvwi9heuaxGg==", + "dev": true, + "requires": { + "eventemitter3": "4.0.4" + } + }, + "web3-core-requestmanager": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.8.2.tgz", + "integrity": "sha512-p1d090RYs5Mu7DK1yyc3GCBVZB/03rBtFhYFoS2EruGzOWs/5Q0grgtpwS/DScdRAm8wB8mYEBhY/RKJWF6B2g==", + "dev": true, + "requires": { + "util": "^0.12.5", + "web3-core-helpers": "1.8.2", + "web3-providers-http": "1.8.2", + "web3-providers-ipc": "1.8.2", + "web3-providers-ws": "1.8.2" + } + }, + "web3-core-subscriptions": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.8.2.tgz", + "integrity": "sha512-vXQogHDmAIQcKpXvGiMddBUeP9lnKgYF64+yQJhPNE5PnWr1sAibXuIPV7mIPihpFr/n/DORRj6Wh1pUv9zaTw==", + "dev": true, + "requires": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.8.2" + } + }, + "web3-eth": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.8.2.tgz", + "integrity": "sha512-JoTiWWc4F4TInpbvDUGb0WgDYJsFhuIjJlinc5ByjWD88Gvh+GKLsRjjFdbqe5YtwIGT4NymwoC5LQd1K6u/QQ==", + "dev": true, + "requires": { + "web3-core": "1.8.2", + "web3-core-helpers": "1.8.2", + "web3-core-method": "1.8.2", + "web3-core-subscriptions": "1.8.2", + "web3-eth-abi": "1.8.2", + "web3-eth-accounts": "1.8.2", + "web3-eth-contract": "1.8.2", + "web3-eth-ens": "1.8.2", + "web3-eth-iban": "1.8.2", + "web3-eth-personal": "1.8.2", + "web3-net": "1.8.2", + "web3-utils": "1.8.2" + } + }, + "web3-eth-abi": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.8.2.tgz", + "integrity": "sha512-Om9g3kaRNjqiNPAgKwGT16y+ZwtBzRe4ZJFGjLiSs6v5I7TPNF+rRMWuKnR6jq0azQZDj6rblvKFMA49/k48Og==", + "dev": true, + "requires": { + "@ethersproject/abi": "^5.6.3", + "web3-utils": "1.8.2" + } + }, + "web3-eth-accounts": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.8.2.tgz", + "integrity": "sha512-c367Ij63VCz9YdyjiHHWLFtN85l6QghgwMQH2B1eM/p9Y5lTlTX7t/Eg/8+f1yoIStXbk2w/PYM2lk+IkbqdLA==", + "dev": true, + "requires": { + "@ethereumjs/common": "2.5.0", + "@ethereumjs/tx": "3.3.2", + "eth-lib": "0.2.8", + "ethereumjs-util": "^7.1.5", + "scrypt-js": "^3.0.1", + "uuid": "^9.0.0", + "web3-core": "1.8.2", + "web3-core-helpers": "1.8.2", + "web3-core-method": "1.8.2", + "web3-utils": "1.8.2" + } + }, + "web3-eth-contract": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.8.2.tgz", + "integrity": "sha512-ID5A25tHTSBNwOPjiXSVzxruz006ULRIDbzWTYIFTp7NJ7vXu/kynKK2ag/ObuTqBpMbobP8nXcA9b5EDkIdQA==", + "dev": true, + "requires": { + "@types/bn.js": "^5.1.0", + "web3-core": "1.8.2", + "web3-core-helpers": "1.8.2", + "web3-core-method": "1.8.2", + "web3-core-promievent": "1.8.2", + "web3-core-subscriptions": "1.8.2", + "web3-eth-abi": "1.8.2", + "web3-utils": "1.8.2" + } + }, + "web3-eth-ens": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.8.2.tgz", + "integrity": "sha512-PWph7C/CnqdWuu1+SH4U4zdrK4t2HNt0I4XzPYFdv9ugE8EuojselioPQXsVGvjql+Nt3jDLvQvggPqlMbvwRw==", + "dev": true, + "requires": { + "content-hash": "^2.5.2", + "eth-ens-namehash": "2.0.8", + "web3-core": "1.8.2", + "web3-core-helpers": "1.8.2", + "web3-core-promievent": "1.8.2", + "web3-eth-abi": "1.8.2", + "web3-eth-contract": "1.8.2", + "web3-utils": "1.8.2" + } + }, + "web3-eth-iban": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.8.2.tgz", + "integrity": "sha512-h3vNblDWkWMuYx93Q27TAJz6lhzpP93EiC3+45D6xoz983p6si773vntoQ+H+5aZhwglBtoiBzdh7PSSOnP/xQ==", + "dev": true, + "requires": { + "bn.js": "^5.2.1", + "web3-utils": "1.8.2" + } + }, + "web3-eth-personal": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.8.2.tgz", + "integrity": "sha512-Vg4HfwCr7doiUF/RC+Jz0wT4+cYaXcOWMAW2AHIjHX6Z7Xwa8nrURIeQgeEE62qcEHAzajyAdB1u6bJyTfuCXw==", + "dev": true, + "requires": { + "@types/node": "^12.12.6", + "web3-core": "1.8.2", + "web3-core-helpers": "1.8.2", + "web3-core-method": "1.8.2", + "web3-net": "1.8.2", + "web3-utils": "1.8.2" + } + }, + "web3-net": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.8.2.tgz", + "integrity": "sha512-1itkDMGmbgb83Dg9nporFes9/fxsU7smJ3oRXlFkg4ZHn8YJyP1MSQFPJWWwSc+GrcCFt4O5IrUTvEkHqE3xag==", + "dev": true, + "requires": { + "web3-core": "1.8.2", + "web3-core-method": "1.8.2", + "web3-utils": "1.8.2" + } + }, + "web3-providers-http": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.8.2.tgz", + "integrity": "sha512-2xY94IIEQd16+b+vIBF4IC1p7GVaz9q4EUFscvMUjtEq4ru4Atdzjs9GP+jmcoo49p70II0UV3bqQcz0TQfVyQ==", + "dev": true, + "requires": { + "abortcontroller-polyfill": "^1.7.3", + "cross-fetch": "^3.1.4", + "es6-promise": "^4.2.8", + "web3-core-helpers": "1.8.2" + } + }, + "web3-providers-ipc": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.8.2.tgz", + "integrity": "sha512-p6fqKVGFg+WiXGHWnB1hu43PbvPkDHTz4RgoEzbXugv5rtv5zfYLqm8Ba6lrJOS5ks9kGKR21a0y3NzE3u7V4w==", + "dev": true, + "requires": { + "oboe": "2.1.5", + "web3-core-helpers": "1.8.2" + } + }, + "web3-providers-ws": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.8.2.tgz", + "integrity": "sha512-3s/4K+wHgbiN+Zrp9YjMq2eqAF6QGABw7wFftPdx+m5hWImV27/MoIx57c6HffNRqZXmCHnfWWFCNHHsi7wXnA==", + "dev": true, + "requires": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.8.2", + "websocket": "^1.0.32" + } + }, + "web3-shh": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.8.2.tgz", + "integrity": "sha512-uZ+3MAoNcaJsXXNCDnizKJ5viBNeHOFYsCbFhV755Uu52FswzTOw6DtE7yK9nYXMtIhiSgi7nwl1RYzP8pystw==", + "dev": true, + "requires": { + "web3-core": "1.8.2", + "web3-core-method": "1.8.2", + "web3-core-subscriptions": "1.8.2", + "web3-net": "1.8.2" + } + }, + "web3-utils": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.8.2.tgz", + "integrity": "sha512-v7j6xhfLQfY7xQDrUP0BKbaNrmZ2/+egbqP9q3KYmOiPpnvAfol+32slgL0WX/5n8VPvKCK5EZ1HGrAVICSToA==", + "dev": true, + "requires": { + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereumjs-util": "^7.1.0", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + } } } }, @@ -17189,12 +18925,6 @@ } } }, - "@types/async-eventemitter": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@types/async-eventemitter/-/async-eventemitter-0.2.1.tgz", - "integrity": "sha512-M2P4Ng26QbAeITiH7w1d7OxtldgfAe0wobpyJzVK/XOb0cUGKU2R4pfAhqcJBXAe2ife5ZOhSv4wk7p+ffURtg==", - "dev": true - }, "@types/bignumber.js": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/@types/bignumber.js/-/bignumber.js-5.0.0.tgz", @@ -17226,9 +18956,9 @@ } }, "@types/chai": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.4.tgz", - "integrity": "sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz", + "integrity": "sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==", "dev": true }, "@types/concat-stream": { @@ -17328,6 +19058,24 @@ "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", "dev": true }, + "@types/readable-stream": { + "version": "2.3.15", + "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-2.3.15.tgz", + "integrity": "sha512-oM5JSKQCcICF1wvGgmecmHldZ48OZamtMxcGGVICOJA8o8cahXC1zEVAif8iwoc5j8etxFaRFnf095+CDsuoFQ==", + "dev": true, + "requires": { + "@types/node": "*", + "safe-buffer": "~5.1.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } + } + }, "@types/responselike": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", @@ -17647,22 +19395,10 @@ "dev": true }, "async": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "dev": true, - "requires": { - "lodash": "^4.17.14" - } - }, - "async-eventemitter": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/async-eventemitter/-/async-eventemitter-0.2.4.tgz", - "integrity": "sha512-pd20BwL7Yt1zwDFy+8MX8F1+WCT8aQeKj0kQnTrH9WaeRETlRamVhD0JtRPmrV4GfOJ2F9CvdQkZeZhnh2TuHw==", - "dev": true, - "requires": { - "async": "^2.4.0" - } + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==", + "dev": true }, "async-limiter": { "version": "1.0.1", @@ -17760,18 +19496,9 @@ "dev": true }, "bigint-crypto-utils": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/bigint-crypto-utils/-/bigint-crypto-utils-3.1.8.tgz", - "integrity": "sha512-+VMV9Laq8pXLBKKKK49nOoq9bfR3j7NNQAtbA617a4nw9bVLo8rsqkKMBgM2AJWlNX9fEIyYaYX+d0laqYV4tw==", - "dev": true, - "requires": { - "bigint-mod-arith": "^3.1.0" - } - }, - "bigint-mod-arith": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bigint-mod-arith/-/bigint-mod-arith-3.1.2.tgz", - "integrity": "sha512-nx8J8bBeiRR+NlsROFH9jHswW5HO8mgfOSqW0AmjicMMvaONDa8AO+5ViKDUUNytBPWiwfvZP4/Bj4Y3lUfvgQ==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/bigint-crypto-utils/-/bigint-crypto-utils-3.2.2.tgz", + "integrity": "sha512-U1RbE3aX9ayCUVcIPHuPDPKcK3SFOXf93J1UK/iHlJuQB7bhagPIX06/CLpLEsDThJ7KA4Dhrnzynl+d2weTiw==", "dev": true }, "bignumber.js": { @@ -18089,6 +19816,12 @@ } } }, + "case": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/case/-/case-1.6.3.tgz", + "integrity": "sha512-mzDSXIPaFwVDvZAHqZ9VlbyF4yyXRuX6IvB06WvPYkqJVO24kX1PPhv9bfpKNFZyxYFmmgo03HUiD8iklmJYRQ==", + "dev": true + }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -18286,15 +20019,15 @@ "dev": true }, "classic-level": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/classic-level/-/classic-level-1.2.0.tgz", - "integrity": "sha512-qw5B31ANxSluWz9xBzklRWTUAJ1SXIdaVKTVS7HcTGKOAmExx65Wo5BUICW+YGORe2FOUaDghoI9ZDxj82QcFg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/classic-level/-/classic-level-1.3.0.tgz", + "integrity": "sha512-iwFAJQYtqRTRM0F6L8h4JCt00ZSGdOyqh7yVrhhjrOpFhmBjNlRUey64MCiyo6UmQHMJ+No3c81nujPv+n9yrg==", "dev": true, "requires": { "abstract-level": "^1.0.2", "catering": "^2.1.0", "module-error": "^1.0.1", - "napi-macros": "~2.0.0", + "napi-macros": "^2.2.2", "node-gyp-build": "^4.3.0" } }, @@ -18418,9 +20151,9 @@ "dev": true }, "commander": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.0.tgz", - "integrity": "sha512-zS5PnTI22FIRM6ylNW8G4Ap0IEOyk62fhLSD0+uHRT9McRCLGpkVNvao4bjimpK/GShynyQkFFxHhwMcETmduA==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", "dev": true }, "compare-versions": { @@ -18544,9 +20277,9 @@ } }, "cosmiconfig": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.1.0.tgz", - "integrity": "sha512-0tLZ9URlPGU7JsKq0DQOQ3FoRsYX8xDZ7xMiATQfaiGMz7EHowNkbU9u1coAOmnh9p/1ySpm0RB3JNWRXM5GCg==", + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.1.3.tgz", + "integrity": "sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==", "dev": true, "requires": { "import-fresh": "^3.2.1", @@ -18939,14 +20672,14 @@ } }, "domutils": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", - "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", "dev": true, "requires": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", - "domhandler": "^5.0.1" + "domhandler": "^5.0.3" } }, "dot-case": { @@ -19026,9 +20759,9 @@ } }, "entities": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", - "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "dev": true }, "env-paths": { @@ -19248,15 +20981,15 @@ } }, "eslint": { - "version": "8.36.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.36.0.tgz", - "integrity": "sha512-Y956lmS7vDqomxlaaQAHVmeb4tNMp2FWIvU/RnU5BD3IKMD/MJPr76xdyr68P8tV1iNMvN2mRK0yy3c+UjL+bw==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.39.0.tgz", + "integrity": "sha512-mwiok6cy7KTW7rBpo05k6+p4YVZByLNjAZ/ACB9DRCu4YDRwjXI01tWHp6KAUWelsBetTxKK/2sHB0vdS8Z2Og==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.1", - "@eslint/js": "8.36.0", + "@eslint/eslintrc": "^2.0.2", + "@eslint/js": "8.39.0", "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -19266,9 +20999,9 @@ "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.5.0", + "eslint-scope": "^7.2.0", + "eslint-visitor-keys": "^3.4.0", + "espree": "^9.5.1", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -19420,16 +21153,16 @@ } }, "eslint-config-prettier": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.7.0.tgz", - "integrity": "sha512-HHVXLSlVUhMSmyW4ZzEuvjpwqamgmlfkutD53cYXLikh4pt/modINRcCIApJ84czDxM4GZInwUrromsDdTImTA==", + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz", + "integrity": "sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==", "dev": true, "requires": {} }, "eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", + "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", "dev": true, "requires": { "esrecurse": "^4.3.0", @@ -19437,20 +21170,20 @@ } }, "eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", + "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", "dev": true }, "espree": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.0.tgz", - "integrity": "sha512-JPbJGhKc47++oo4JkEoTe2wjy4fmMwvFpgJT9cQzmfXKp22Dr6Hf1tdCteLz1h0P3t+mGvWZ+4Uankvh8+c6zw==", + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", + "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", "dev": true, "requires": { "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.0" } }, "esprima": { @@ -20839,9 +22572,9 @@ } }, "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, "grapheme-splitter": { @@ -20909,23 +22642,23 @@ "dev": true }, "hardhat": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.13.0.tgz", - "integrity": "sha512-ZlzBOLML1QGlm6JWyVAG8lVTEAoOaVm1in/RU2zoGAnYEoD1Rp4T+ZMvrLNhHaaeS9hfjJ1gJUBfiDr4cx+htQ==", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.14.0.tgz", + "integrity": "sha512-73jsInY4zZahMSVFurSK+5TNCJTXMv+vemvGia0Ac34Mm19fYp6vEPVGF3sucbumszsYxiTT2TbS8Ii2dsDSoQ==", "dev": true, "requires": { "@ethersproject/abi": "^5.1.2", "@metamask/eth-sig-util": "^4.0.0", - "@nomicfoundation/ethereumjs-block": "^4.0.0", - "@nomicfoundation/ethereumjs-blockchain": "^6.0.0", - "@nomicfoundation/ethereumjs-common": "^3.0.0", - "@nomicfoundation/ethereumjs-evm": "^1.0.0", - "@nomicfoundation/ethereumjs-rlp": "^4.0.0", - "@nomicfoundation/ethereumjs-statemanager": "^1.0.0", - "@nomicfoundation/ethereumjs-trie": "^5.0.0", - "@nomicfoundation/ethereumjs-tx": "^4.0.0", - "@nomicfoundation/ethereumjs-util": "^8.0.0", - "@nomicfoundation/ethereumjs-vm": "^6.0.0", + "@nomicfoundation/ethereumjs-block": "5.0.1", + "@nomicfoundation/ethereumjs-blockchain": "7.0.1", + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-evm": "2.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-statemanager": "2.0.1", + "@nomicfoundation/ethereumjs-trie": "6.0.1", + "@nomicfoundation/ethereumjs-tx": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "@nomicfoundation/ethereumjs-vm": "7.0.1", "@nomicfoundation/solidity-analyzer": "^0.1.0", "@sentry/node": "^5.18.1", "@types/bn.js": "^5.1.0", @@ -21299,15 +23032,15 @@ "dev": true }, "htmlparser2": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz", - "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", "dev": true, "requires": { "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", + "domhandler": "^5.0.3", "domutils": "^3.0.1", - "entities": "^4.3.0" + "entities": "^4.4.0" } }, "http-basic": { @@ -21830,9 +23563,9 @@ "dev": true }, "js-sdsl": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", - "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", + "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", "dev": true }, "js-sha3": { @@ -22495,9 +24228,9 @@ } }, "mixme": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mixme/-/mixme-0.5.5.tgz", - "integrity": "sha512-/6IupbRx32s7jjEwHcycXikJwFD5UujbVNuJFkeKLYje+92OvtuPniF6JhnFm5JCTDUhS+kYK3W/4BWYQYXz7w==", + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/mixme/-/mixme-0.5.9.tgz", + "integrity": "sha512-VC5fg6ySUscaWUpI4gxCBTQMH2RdUpNrk+MsbpCYtIvf9SBJdiUey4qE7BXviJsJR4nDQxCZ+3yaYNW3guz/Pw==", "dev": true }, "mkdirp": { @@ -22822,9 +24555,9 @@ "dev": true }, "napi-macros": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz", - "integrity": "sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.2.2.tgz", + "integrity": "sha512-hmEVtAGYzVQpCKdbQea4skABsdXW4RUh5t5mJ2zzqowJS2OyXZTU1KhDVFhx+NlWZ4ap9mqR9TcDO3LTTttd+g==", "dev": true }, "natural-compare": { @@ -23034,15 +24767,16 @@ } }, "object.getownpropertydescriptors": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.5.tgz", - "integrity": "sha512-yDNzckpM6ntyQiGTik1fKV1DcVDRS+w8bvpWNCBanvH5LfRX9O8WTHqQzG4RZwRAM4I0oU7TV11Lj5v0g20ibw==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.6.tgz", + "integrity": "sha512-lq+61g26E/BgHv0ZTFgRvi7NMEPuAxLkFU7rukXjc/AlwH4Am5xXVnIXy3un1bg/JPbXHrixRkK1itUzzPiIjQ==", "dev": true, "requires": { "array.prototype.reduce": "^1.0.5", "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.21.2", + "safe-array-concat": "^1.0.0" } }, "obliterator": { @@ -23424,9 +25158,9 @@ "dev": true }, "prettier": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", - "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", "dev": true }, "prettier-plugin-solidity": { @@ -23703,14 +25437,14 @@ "dev": true }, "regexp.prototype.flags": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", - "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", + "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", "dev": true, "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" + "define-properties": "^1.2.0", + "functions-have-names": "^1.2.3" } }, "req-cwd": { @@ -23951,6 +25685,26 @@ "integrity": "sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA==", "dev": true }, + "safe-array-concat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.0.tgz", + "integrity": "sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "dependencies": { + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + } + } + }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -23996,12 +25750,6 @@ "wordwrap": "^1.0.0" }, "dependencies": { - "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==", - "dev": true - }, "esprima": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", @@ -24071,9 +25819,9 @@ } }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -26041,18 +27789,18 @@ "dev": true }, "tty-table": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/tty-table/-/tty-table-4.1.6.tgz", - "integrity": "sha512-kRj5CBzOrakV4VRRY5kUWbNYvo/FpOsz65DzI5op9P+cHov3+IqPbo1JE1ZnQGkHdZgNFDsrEjrfqqy/Ply9fw==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/tty-table/-/tty-table-4.2.1.tgz", + "integrity": "sha512-xz0uKo+KakCQ+Dxj1D/tKn2FSyreSYWzdkL/BYhgN6oMW808g8QRMuh1atAV9fjTPbWBjfbkKQpI/5rEcnAc7g==", "dev": true, "requires": { "chalk": "^4.1.2", - "csv": "^5.5.0", - "kleur": "^4.1.4", + "csv": "^5.5.3", + "kleur": "^4.1.5", "smartwrap": "^2.0.2", - "strip-ansi": "^6.0.0", + "strip-ansi": "^6.0.1", "wcwidth": "^1.0.1", - "yargs": "^17.1.1" + "yargs": "^17.7.1" }, "dependencies": { "ansi-regex": { @@ -26237,9 +27985,9 @@ "dev": true }, "undici": { - "version": "5.21.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.21.0.tgz", - "integrity": "sha512-HOjK8l6a57b2ZGXOcUsI5NLfoTrfmbOl90ixJDl0AEFG4wgHNDQxtZy15/ZQp7HhjkpaGlp/eneMgtsu1dIlUA==", + "version": "5.22.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.0.tgz", + "integrity": "sha512-fR9RXCc+6Dxav4P9VV/sp5w3eFiSdOjJYsbtWfd4s5L5C4ogyuVpdKIVHeW0vV1MloM65/f7W45nR9ZxwVdyiA==", "dev": true, "requires": { "busboy": "^1.6.0" @@ -26376,24 +28124,24 @@ } }, "web3": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3/-/web3-1.8.2.tgz", - "integrity": "sha512-92h0GdEHW9wqDICQQKyG4foZBYi0OQkyg4CRml2F7XBl/NG+fu9o6J19kzfFXzSBoA4DnJXbyRgj/RHZv5LRiw==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.9.0.tgz", + "integrity": "sha512-E9IvVy/d2ozfQQsCiV+zh/LmlZGv9fQxI0UedDVjm87yOKf4AYbBNEn1iWtHveiGzAk2CEMZMUzAZzaQNSSYog==", "dev": true, "requires": { - "web3-bzz": "1.8.2", - "web3-core": "1.8.2", - "web3-eth": "1.8.2", - "web3-eth-personal": "1.8.2", - "web3-net": "1.8.2", - "web3-shh": "1.8.2", - "web3-utils": "1.8.2" + "web3-bzz": "1.9.0", + "web3-core": "1.9.0", + "web3-eth": "1.9.0", + "web3-eth-personal": "1.9.0", + "web3-net": "1.9.0", + "web3-shh": "1.9.0", + "web3-utils": "1.9.0" } }, "web3-bzz": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.8.2.tgz", - "integrity": "sha512-1EEnxjPnFnvNWw3XeeKuTR8PBxYd0+XWzvaLK7OJC/Go9O8llLGxrxICbKV+8cgIE0sDRBxiYx02X+6OhoAQ9w==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.9.0.tgz", + "integrity": "sha512-9Zli9dikX8GdHwBb5/WPzpSVuy3EWMKY3P4EokCQra31fD7DLizqAAaTUsFwnK7xYkw5ogpHgelw9uKHHzNajg==", "dev": true, "requires": { "@types/node": "^12.12.6", @@ -26402,18 +28150,18 @@ } }, "web3-core": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.8.2.tgz", - "integrity": "sha512-DJTVEAYcNqxkqruJE+Rxp3CIv0y5AZMwPHQmOkz/cz+MM75SIzMTc0AUdXzGyTS8xMF8h3YWMQGgGEy8SBf1PQ==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.9.0.tgz", + "integrity": "sha512-DZ+TPmq/ZLlx4LSVzFgrHCP/QFpKDbGWO4HoquZSdu24cjk5SZ+FEU1SZB2OaK3/bgBh+25mRbmv8y56ysUu1w==", "dev": true, "requires": { - "@types/bn.js": "^5.1.0", + "@types/bn.js": "^5.1.1", "@types/node": "^12.12.6", "bignumber.js": "^9.0.0", - "web3-core-helpers": "1.8.2", - "web3-core-method": "1.8.2", - "web3-core-requestmanager": "1.8.2", - "web3-utils": "1.8.2" + "web3-core-helpers": "1.9.0", + "web3-core-method": "1.9.0", + "web3-core-requestmanager": "1.9.0", + "web3-utils": "1.9.0" }, "dependencies": { "bignumber.js": { @@ -26425,94 +28173,94 @@ } }, "web3-core-helpers": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.8.2.tgz", - "integrity": "sha512-6B1eLlq9JFrfealZBomd1fmlq1o4A09vrCVQSa51ANoib/jllT3atZrRDr0zt1rfI7TSZTZBXdN/aTdeN99DWw==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.9.0.tgz", + "integrity": "sha512-NeJzylAp9Yj9xAt2uTT+kyug3X0DLnfBdnAcGZuY6HhoNPDIfQRA9CkJjLngVRlGTLZGjNp9x9eR+RyZQgUlXg==", "dev": true, "requires": { - "web3-eth-iban": "1.8.2", - "web3-utils": "1.8.2" + "web3-eth-iban": "1.9.0", + "web3-utils": "1.9.0" } }, "web3-core-method": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.8.2.tgz", - "integrity": "sha512-1qnr5mw5wVyULzLOrk4B+ryO3gfGjGd/fx8NR+J2xCGLf1e6OSjxT9vbfuQ3fErk/NjSTWWreieYWLMhaogcRA==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.9.0.tgz", + "integrity": "sha512-sswbNsY2xRBBhGeaLt9c/eDc+0yDDhi6keUBAkgIRa9ueSx/VKzUY9HMqiV6bXDcGT2fJyejq74FfEB4lc/+/w==", "dev": true, "requires": { "@ethersproject/transactions": "^5.6.2", - "web3-core-helpers": "1.8.2", - "web3-core-promievent": "1.8.2", - "web3-core-subscriptions": "1.8.2", - "web3-utils": "1.8.2" + "web3-core-helpers": "1.9.0", + "web3-core-promievent": "1.9.0", + "web3-core-subscriptions": "1.9.0", + "web3-utils": "1.9.0" } }, "web3-core-promievent": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.8.2.tgz", - "integrity": "sha512-nvkJWDVgoOSsolJldN33tKW6bKKRJX3MCPDYMwP5SUFOA/mCzDEoI88N0JFofDTXkh1k7gOqp1pvwi9heuaxGg==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.9.0.tgz", + "integrity": "sha512-PHG1Mn23IGwMZhnPDN8dETKypqsFbHfiyRqP+XsVMPmTHkVfzDQTCBU/c2r6hUktBDoGKut5xZQpGfhFk71KbQ==", "dev": true, "requires": { "eventemitter3": "4.0.4" } }, "web3-core-requestmanager": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.8.2.tgz", - "integrity": "sha512-p1d090RYs5Mu7DK1yyc3GCBVZB/03rBtFhYFoS2EruGzOWs/5Q0grgtpwS/DScdRAm8wB8mYEBhY/RKJWF6B2g==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.9.0.tgz", + "integrity": "sha512-hcJ5PCtTIJpj+8qWxoseqlCovDo94JJjTX7dZOLXgwp8ah7E3WRYozhGyZocerx+KebKyg1mCQIhkDpMwjfo9Q==", "dev": true, "requires": { "util": "^0.12.5", - "web3-core-helpers": "1.8.2", - "web3-providers-http": "1.8.2", - "web3-providers-ipc": "1.8.2", - "web3-providers-ws": "1.8.2" + "web3-core-helpers": "1.9.0", + "web3-providers-http": "1.9.0", + "web3-providers-ipc": "1.9.0", + "web3-providers-ws": "1.9.0" } }, "web3-core-subscriptions": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.8.2.tgz", - "integrity": "sha512-vXQogHDmAIQcKpXvGiMddBUeP9lnKgYF64+yQJhPNE5PnWr1sAibXuIPV7mIPihpFr/n/DORRj6Wh1pUv9zaTw==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.9.0.tgz", + "integrity": "sha512-MaIo29yz7hTV8X8bioclPDbHFOVuHmnbMv+D3PDH12ceJFJAXGyW8GL5KU1DYyWIj4TD1HM4WknyVA/YWBiiLA==", "dev": true, "requires": { "eventemitter3": "4.0.4", - "web3-core-helpers": "1.8.2" + "web3-core-helpers": "1.9.0" } }, "web3-eth": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.8.2.tgz", - "integrity": "sha512-JoTiWWc4F4TInpbvDUGb0WgDYJsFhuIjJlinc5ByjWD88Gvh+GKLsRjjFdbqe5YtwIGT4NymwoC5LQd1K6u/QQ==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.9.0.tgz", + "integrity": "sha512-c5gSWk9bLNr6VPATHmZ1n7LTIefIZQnJMzfnvkoBcIFGKJbGmsuRhv6lEXsKdAO/FlqYnSbaw3fOq1fVFiIOFQ==", "dev": true, "requires": { - "web3-core": "1.8.2", - "web3-core-helpers": "1.8.2", - "web3-core-method": "1.8.2", - "web3-core-subscriptions": "1.8.2", - "web3-eth-abi": "1.8.2", - "web3-eth-accounts": "1.8.2", - "web3-eth-contract": "1.8.2", - "web3-eth-ens": "1.8.2", - "web3-eth-iban": "1.8.2", - "web3-eth-personal": "1.8.2", - "web3-net": "1.8.2", - "web3-utils": "1.8.2" + "web3-core": "1.9.0", + "web3-core-helpers": "1.9.0", + "web3-core-method": "1.9.0", + "web3-core-subscriptions": "1.9.0", + "web3-eth-abi": "1.9.0", + "web3-eth-accounts": "1.9.0", + "web3-eth-contract": "1.9.0", + "web3-eth-ens": "1.9.0", + "web3-eth-iban": "1.9.0", + "web3-eth-personal": "1.9.0", + "web3-net": "1.9.0", + "web3-utils": "1.9.0" } }, "web3-eth-abi": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.8.2.tgz", - "integrity": "sha512-Om9g3kaRNjqiNPAgKwGT16y+ZwtBzRe4ZJFGjLiSs6v5I7TPNF+rRMWuKnR6jq0azQZDj6rblvKFMA49/k48Og==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.9.0.tgz", + "integrity": "sha512-0BLQ3FKMrzJkA930jOX3fMaybAyubk06HChclLpiR0NWmgWXm1tmBrJdkyRy2ZTZpmfuZc9xTFRfl0yZID1voA==", "dev": true, "requires": { "@ethersproject/abi": "^5.6.3", - "web3-utils": "1.8.2" + "web3-utils": "1.9.0" } }, "web3-eth-accounts": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.8.2.tgz", - "integrity": "sha512-c367Ij63VCz9YdyjiHHWLFtN85l6QghgwMQH2B1eM/p9Y5lTlTX7t/Eg/8+f1yoIStXbk2w/PYM2lk+IkbqdLA==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.9.0.tgz", + "integrity": "sha512-VeIZVevmnSll0AC1k5F/y398ZE89d1SRuYk8IewLUhL/tVAsFEsjl2SGgm0+aDcHmgPrkW+qsCJ+C7rWg/N4ZA==", "dev": true, "requires": { "@ethereumjs/common": "2.5.0", @@ -26521,10 +28269,10 @@ "ethereumjs-util": "^7.1.5", "scrypt-js": "^3.0.1", "uuid": "^9.0.0", - "web3-core": "1.8.2", - "web3-core-helpers": "1.8.2", - "web3-core-method": "1.8.2", - "web3-utils": "1.8.2" + "web3-core": "1.9.0", + "web3-core-helpers": "1.9.0", + "web3-core-method": "1.9.0", + "web3-utils": "1.9.0" }, "dependencies": { "eth-lib": { @@ -26547,45 +28295,45 @@ } }, "web3-eth-contract": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.8.2.tgz", - "integrity": "sha512-ID5A25tHTSBNwOPjiXSVzxruz006ULRIDbzWTYIFTp7NJ7vXu/kynKK2ag/ObuTqBpMbobP8nXcA9b5EDkIdQA==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.9.0.tgz", + "integrity": "sha512-+j26hpSaEtAdUed0TN5rnc+YZOcjPxMjFX4ZBKatvFkImdbVv/tzTvcHlltubSpgb2ZLyZ89lSL6phKYwd2zNQ==", "dev": true, "requires": { - "@types/bn.js": "^5.1.0", - "web3-core": "1.8.2", - "web3-core-helpers": "1.8.2", - "web3-core-method": "1.8.2", - "web3-core-promievent": "1.8.2", - "web3-core-subscriptions": "1.8.2", - "web3-eth-abi": "1.8.2", - "web3-utils": "1.8.2" + "@types/bn.js": "^5.1.1", + "web3-core": "1.9.0", + "web3-core-helpers": "1.9.0", + "web3-core-method": "1.9.0", + "web3-core-promievent": "1.9.0", + "web3-core-subscriptions": "1.9.0", + "web3-eth-abi": "1.9.0", + "web3-utils": "1.9.0" } }, "web3-eth-ens": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.8.2.tgz", - "integrity": "sha512-PWph7C/CnqdWuu1+SH4U4zdrK4t2HNt0I4XzPYFdv9ugE8EuojselioPQXsVGvjql+Nt3jDLvQvggPqlMbvwRw==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.9.0.tgz", + "integrity": "sha512-LOJZeN+AGe9arhuExnrPPFYQr4WSxXEkpvYIlst/joOEUNLDwfndHnJIK6PI5mXaYSROBtTx6erv+HupzGo7vA==", "dev": true, "requires": { "content-hash": "^2.5.2", "eth-ens-namehash": "2.0.8", - "web3-core": "1.8.2", - "web3-core-helpers": "1.8.2", - "web3-core-promievent": "1.8.2", - "web3-eth-abi": "1.8.2", - "web3-eth-contract": "1.8.2", - "web3-utils": "1.8.2" + "web3-core": "1.9.0", + "web3-core-helpers": "1.9.0", + "web3-core-promievent": "1.9.0", + "web3-eth-abi": "1.9.0", + "web3-eth-contract": "1.9.0", + "web3-utils": "1.9.0" } }, "web3-eth-iban": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.8.2.tgz", - "integrity": "sha512-h3vNblDWkWMuYx93Q27TAJz6lhzpP93EiC3+45D6xoz983p6si773vntoQ+H+5aZhwglBtoiBzdh7PSSOnP/xQ==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.9.0.tgz", + "integrity": "sha512-jPAm77PuEs1kE/UrrBFJdPD2PN42pwfXA0gFuuw35bZezhskYML9W4QCxcqnUtceyEA4FUn7K2qTMuCk+23fog==", "dev": true, "requires": { "bn.js": "^5.2.1", - "web3-utils": "1.8.2" + "web3-utils": "1.9.0" }, "dependencies": { "bn.js": { @@ -26597,79 +28345,79 @@ } }, "web3-eth-personal": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.8.2.tgz", - "integrity": "sha512-Vg4HfwCr7doiUF/RC+Jz0wT4+cYaXcOWMAW2AHIjHX6Z7Xwa8nrURIeQgeEE62qcEHAzajyAdB1u6bJyTfuCXw==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.9.0.tgz", + "integrity": "sha512-r9Ldo/luBqJlv1vCUEQnUS+C3a3ZdbYxVHyfDkj6RWMyCqqo8JE41HWE+pfa0RmB1xnGL2g8TbYcHcqItck/qg==", "dev": true, "requires": { "@types/node": "^12.12.6", - "web3-core": "1.8.2", - "web3-core-helpers": "1.8.2", - "web3-core-method": "1.8.2", - "web3-net": "1.8.2", - "web3-utils": "1.8.2" + "web3-core": "1.9.0", + "web3-core-helpers": "1.9.0", + "web3-core-method": "1.9.0", + "web3-net": "1.9.0", + "web3-utils": "1.9.0" } }, "web3-net": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.8.2.tgz", - "integrity": "sha512-1itkDMGmbgb83Dg9nporFes9/fxsU7smJ3oRXlFkg4ZHn8YJyP1MSQFPJWWwSc+GrcCFt4O5IrUTvEkHqE3xag==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.9.0.tgz", + "integrity": "sha512-L+fDZFgrLM5Y15aonl2q6L+RvfaImAngmC0Jv45hV2FJ5IfRT0/2ob9etxZmvEBWvOpbqSvghfOhJIT3XZ37Pg==", "dev": true, "requires": { - "web3-core": "1.8.2", - "web3-core-method": "1.8.2", - "web3-utils": "1.8.2" + "web3-core": "1.9.0", + "web3-core-method": "1.9.0", + "web3-utils": "1.9.0" } }, "web3-providers-http": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.8.2.tgz", - "integrity": "sha512-2xY94IIEQd16+b+vIBF4IC1p7GVaz9q4EUFscvMUjtEq4ru4Atdzjs9GP+jmcoo49p70II0UV3bqQcz0TQfVyQ==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.9.0.tgz", + "integrity": "sha512-5+dMNDAE0rRFz6SJpfnBqlVi2J5bB/Ivr2SanMt2YUrkxW5t8betZbzVwRkTbwtUvkqgj3xeUQzqpOttiv+IqQ==", "dev": true, "requires": { "abortcontroller-polyfill": "^1.7.3", "cross-fetch": "^3.1.4", "es6-promise": "^4.2.8", - "web3-core-helpers": "1.8.2" + "web3-core-helpers": "1.9.0" } }, "web3-providers-ipc": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.8.2.tgz", - "integrity": "sha512-p6fqKVGFg+WiXGHWnB1hu43PbvPkDHTz4RgoEzbXugv5rtv5zfYLqm8Ba6lrJOS5ks9kGKR21a0y3NzE3u7V4w==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.9.0.tgz", + "integrity": "sha512-cPXU93Du40HCylvjaa5x62DbnGqH+86HpK/+kMcFIzF6sDUBhKpag2tSbYhGbj7GMpfkmDTUiiMLdWnFV6+uBA==", "dev": true, "requires": { "oboe": "2.1.5", - "web3-core-helpers": "1.8.2" + "web3-core-helpers": "1.9.0" } }, "web3-providers-ws": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.8.2.tgz", - "integrity": "sha512-3s/4K+wHgbiN+Zrp9YjMq2eqAF6QGABw7wFftPdx+m5hWImV27/MoIx57c6HffNRqZXmCHnfWWFCNHHsi7wXnA==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.9.0.tgz", + "integrity": "sha512-JRVsnQZ7j2k1a2yzBNHe39xqk1ijOv01dfIBFw52VeEkSRzvrOcsPIM/ttSyBuJqt70ntMxXY0ekCrqfleKH/w==", "dev": true, "requires": { "eventemitter3": "4.0.4", - "web3-core-helpers": "1.8.2", + "web3-core-helpers": "1.9.0", "websocket": "^1.0.32" } }, "web3-shh": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.8.2.tgz", - "integrity": "sha512-uZ+3MAoNcaJsXXNCDnizKJ5viBNeHOFYsCbFhV755Uu52FswzTOw6DtE7yK9nYXMtIhiSgi7nwl1RYzP8pystw==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.9.0.tgz", + "integrity": "sha512-bIBZlralgz4ICCrwkefB2nPPJWfx28NuHIpjB7d9ADKynElubQuqudYhKtSEkKXACuME/BJm0pIFJcJs/gDnMg==", "dev": true, "requires": { - "web3-core": "1.8.2", - "web3-core-method": "1.8.2", - "web3-core-subscriptions": "1.8.2", - "web3-net": "1.8.2" + "web3-core": "1.9.0", + "web3-core-method": "1.9.0", + "web3-core-subscriptions": "1.9.0", + "web3-net": "1.9.0" } }, "web3-utils": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.8.2.tgz", - "integrity": "sha512-v7j6xhfLQfY7xQDrUP0BKbaNrmZ2/+egbqP9q3KYmOiPpnvAfol+32slgL0WX/5n8VPvKCK5EZ1HGrAVICSToA==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.9.0.tgz", + "integrity": "sha512-p++69rCNNfu2jM9n5+VD/g26l+qkEOQ1m6cfRQCbH8ZRrtquTmrirJMgTmyOoax5a5XRYOuws14aypCOs51pdQ==", "dev": true, "requires": { "bn.js": "^5.2.1", @@ -26759,9 +28507,9 @@ } }, "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", "dev": true }, "which-pm": { @@ -26970,9 +28718,9 @@ "dev": true }, "yargs": { - "version": "17.7.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", - "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, "requires": { "cliui": "^8.0.1", From 34d926dd7e8ba8b6fb306d88a319368050a34bc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Garc=C3=ADa?= Date: Tue, 9 May 2023 18:19:35 +0200 Subject: [PATCH 121/133] Implement extra suggestions from audit review of 4.9 (#4224) --- .../proxy/transparent/TransparentUpgradeableProxy.sol | 2 ++ contracts/utils/Checkpoints.sol | 8 ++++---- contracts/utils/ShortStrings.sol | 10 ++++++++-- scripts/generate/templates/Checkpoints.js | 4 ++-- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/contracts/proxy/transparent/TransparentUpgradeableProxy.sol b/contracts/proxy/transparent/TransparentUpgradeableProxy.sol index 4e2b0c759..e49768ab9 100644 --- a/contracts/proxy/transparent/TransparentUpgradeableProxy.sol +++ b/contracts/proxy/transparent/TransparentUpgradeableProxy.sol @@ -174,6 +174,8 @@ contract TransparentUpgradeableProxy is ERC1967Proxy { /** * @dev Returns the current admin. + * + * CAUTION: This function is deprecated. Use {ERC1967Upgrade-_getAdmin} instead. */ function _admin() internal view virtual returns (address) { return _getAdmin(); diff --git a/contracts/utils/Checkpoints.sol b/contracts/utils/Checkpoints.sol index 27da4b517..1bb66dec9 100644 --- a/contracts/utils/Checkpoints.sol +++ b/contracts/utils/Checkpoints.sol @@ -234,7 +234,7 @@ library Checkpoints { } /** - * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key. + * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero if there is none. */ function upperLookup(Trace224 storage self, uint32 key) internal view returns (uint224) { uint256 len = self._checkpoints.length; @@ -243,7 +243,7 @@ library Checkpoints { } /** - * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key. + * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero if there is none. * * NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high keys). */ @@ -410,7 +410,7 @@ library Checkpoints { } /** - * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key. + * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero if there is none. */ function upperLookup(Trace160 storage self, uint96 key) internal view returns (uint160) { uint256 len = self._checkpoints.length; @@ -419,7 +419,7 @@ library Checkpoints { } /** - * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key. + * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero if there is none. * * NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high keys). */ diff --git a/contracts/utils/ShortStrings.sol b/contracts/utils/ShortStrings.sol index 450c7985e..a8904777a 100644 --- a/contracts/utils/ShortStrings.sol +++ b/contracts/utils/ShortStrings.sol @@ -4,13 +4,18 @@ pragma solidity ^0.8.8; import "./StorageSlot.sol"; +// | string | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | +// | length | 0x BB | type ShortString is bytes32; /** * @dev This library provides functions to convert short memory strings * into a `ShortString` type that can be used as an immutable variable. - * Strings of arbitrary length can be optimized if they are short enough by - * the addition of a storage variable used as fallback. + * + * Strings of arbitrary length can be optimized using this library if + * they are short enough (up to 31 bytes) by packing them with their + * length (1 byte) in a single EVM word (32 bytes). Additionally, a + * fallback mechanism can be used for every other case. * * Usage example: * @@ -32,6 +37,7 @@ type ShortString is bytes32; * ``` */ library ShortStrings { + // Used as an identifier for strings longer than 31 bytes. bytes32 private constant _FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF; error StringTooLong(string str); diff --git a/scripts/generate/templates/Checkpoints.js b/scripts/generate/templates/Checkpoints.js index 1d79031da..8c9f1f850 100644 --- a/scripts/generate/templates/Checkpoints.js +++ b/scripts/generate/templates/Checkpoints.js @@ -55,7 +55,7 @@ function lowerLookup(${opts.historyTypeName} storage self, ${opts.keyTypeName} k } /** - * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key. + * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero if there is none. */ function upperLookup(${opts.historyTypeName} storage self, ${opts.keyTypeName} key) internal view returns (${opts.valueTypeName}) { uint256 len = self.${opts.checkpointFieldName}.length; @@ -64,7 +64,7 @@ function upperLookup(${opts.historyTypeName} storage self, ${opts.keyTypeName} k } /** - * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key. + * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero if there is none. * * NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high keys). */ From 51294b7480fd13e716207a621ac1d55a6290d56d Mon Sep 17 00:00:00 2001 From: Francisco Date: Tue, 9 May 2023 19:52:23 +0100 Subject: [PATCH 122/133] Make transpilation setup local to this repo (#4041) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ernesto García --- .github/workflows/checks.yml | 27 +- .github/workflows/upgradeable.yml | 31 +- contracts/utils/cryptography/EIP712.sol | 6 +- hardhat.config.js | 5 +- hardhat/env-artifacts.js | 24 ++ hardhat/task-test-get-files.js | 35 ++ package-lock.json | 14 +- package.json | 2 +- scripts/upgradeable/README.md | 21 + scripts/upgradeable/patch-apply.sh | 19 + scripts/upgradeable/patch-save.sh | 18 + scripts/upgradeable/transpile-onto.sh | 44 +++ scripts/upgradeable/transpile.sh | 35 ++ scripts/upgradeable/upgradeable.patch | 481 +++++++++++++++++++++++ test/migrate-imports.test.js | 1 + test/utils/Checkpoints.test.js | 161 ++++---- test/utils/cryptography/EIP712.test.js | 6 +- test/utils/structs/EnumerableMap.test.js | 93 ++--- test/utils/structs/EnumerableSet.test.js | 33 +- 19 files changed, 894 insertions(+), 162 deletions(-) create mode 100644 hardhat/env-artifacts.js create mode 100644 hardhat/task-test-get-files.js create mode 100644 scripts/upgradeable/README.md create mode 100755 scripts/upgradeable/patch-apply.sh create mode 100755 scripts/upgradeable/patch-save.sh create mode 100644 scripts/upgradeable/transpile-onto.sh create mode 100644 scripts/upgradeable/transpile.sh create mode 100644 scripts/upgradeable/upgradeable.patch diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 2d5c15159..ae48e9286 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -14,7 +14,6 @@ concurrency: jobs: lint: - if: github.repository != 'OpenZeppelin/openzeppelin-contracts-upgradeable' runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -37,19 +36,36 @@ jobs: - name: Check linearisation of the inheritance graph run: npm run test:inheritance - name: Check proceduraly generated contracts are up-to-date - if: github.repository != 'OpenZeppelin/openzeppelin-contracts-upgradeable' run: npm run test:generation - name: Compare gas costs uses: ./.github/actions/gas-compare with: token: ${{ github.token }} + + tests-upgradeable: + runs-on: ubuntu-latest + env: + FORCE_COLOR: 1 + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 # Include history so patch conflicts are resolved automatically + - name: Set up environment + uses: ./.github/actions/setup + - name: Transpile to upgradeable + run: bash scripts/upgradeable/transpile.sh + - name: Run tests + run: npm run test + env: + NODE_OPTIONS: --max_old_space_size=4096 + - name: Check linearisation of the inheritance graph + run: npm run test:inheritance - name: Check storage layout uses: ./.github/actions/storage-layout with: token: ${{ github.token }} - foundry-tests: - if: github.repository != 'OpenZeppelin/openzeppelin-contracts-upgradeable' + tests-foundry: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -63,7 +79,6 @@ jobs: run: forge test -vv coverage: - if: github.repository != 'OpenZeppelin/openzeppelin-contracts-upgradeable' runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -77,7 +92,6 @@ jobs: token: ${{ secrets.CODECOV_TOKEN }} slither: - if: github.repository != 'OpenZeppelin/openzeppelin-contracts-upgradeable' runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -89,7 +103,6 @@ jobs: node-version: 18.15 codespell: - if: github.repository != 'OpenZeppelin/openzeppelin-contracts-upgradeable' runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/upgradeable.yml b/.github/workflows/upgradeable.yml index a7ed8da88..649596abb 100644 --- a/.github/workflows/upgradeable.yml +++ b/.github/workflows/upgradeable.yml @@ -1,4 +1,4 @@ -name: Upgradeable Trigger +name: transpile upgradeable on: push: @@ -7,17 +7,24 @@ on: - release-v* jobs: - trigger: + transpile: + environment: push-upgradeable runs-on: ubuntu-latest steps: - - id: app - uses: getsentry/action-github-app-token@v2 + - uses: actions/checkout@v3 with: - app_id: ${{ secrets.UPGRADEABLE_APP_ID }} - private_key: ${{ secrets.UPGRADEABLE_APP_PK }} - - run: | - curl -X POST \ - https://api.github.com/repos/OpenZeppelin/openzeppelin-contracts-upgradeable/dispatches \ - -H 'Accept: application/vnd.github.v3+json' \ - -H 'Authorization: token ${{ steps.app.outputs.token }}' \ - -d '{ "event_type": "Update", "client_payload": { "ref": "${{ github.ref }}" } }' + repository: OpenZeppelin/openzeppelin-contracts-upgradeable + fetch-depth: 0 + token: ${{ secrets.GH_TOKEN_UPGRADEABLE }} + - name: Fetch current non-upgradeable branch + run: | + git fetch "https://github.com/${{ github.repository }}.git" "$REF" + git checkout FETCH_HEAD + env: + REF: ${{ github.ref }} + - name: Set up environment + uses: ./.github/actions/setup + - run: bash scripts/git-user-config.sh + - name: Transpile to upgradeable + run: bash scripts/upgradeable/transpile-onto.sh ${{ github.ref_name }} origin/${{ github.ref_name }} + - run: git push origin ${{ github.ref_name }} diff --git a/contracts/utils/cryptography/EIP712.sol b/contracts/utils/cryptography/EIP712.sol index 56dfceaf4..6a4e1cad2 100644 --- a/contracts/utils/cryptography/EIP712.sol +++ b/contracts/utils/cryptography/EIP712.sol @@ -44,14 +44,14 @@ abstract contract EIP712 is IERC5267 { uint256 private immutable _cachedChainId; address private immutable _cachedThis; + bytes32 private immutable _hashedName; + bytes32 private immutable _hashedVersion; + ShortString private immutable _name; ShortString private immutable _version; string private _nameFallback; string private _versionFallback; - bytes32 private immutable _hashedName; - bytes32 private immutable _hashedVersion; - /** * @dev Initializes the domain separator and parameter caches. * diff --git a/hardhat.config.js b/hardhat.config.js index 32f721b65..639e10f95 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -89,10 +89,11 @@ module.exports = { }, }, exposed: { + initializers: true, exclude: [ 'vendor/**/*', - // overflow clash - 'utils/Timers.sol', + // Exclude Timers from hardhat-exposed because its overloaded functions are not transformed correctly + 'utils/Timers{,Upgradeable}.sol', ], }, docgen: require('./docs/config'), diff --git a/hardhat/env-artifacts.js b/hardhat/env-artifacts.js new file mode 100644 index 000000000..fbbea2e2d --- /dev/null +++ b/hardhat/env-artifacts.js @@ -0,0 +1,24 @@ +const { HardhatError } = require('hardhat/internal/core/errors'); + +// Modifies `artifacts.require(X)` so that instead of X it loads the XUpgradeable contract. +// This allows us to run the same test suite on both the original and the transpiled and renamed Upgradeable contracts. + +extendEnvironment(env => { + const artifactsRequire = env.artifacts.require; + + env.artifacts.require = name => { + for (const suffix of ['UpgradeableWithInit', 'Upgradeable', '']) { + try { + return artifactsRequire(name + suffix); + } catch (e) { + // HH700: Artifact not found - from https://hardhat.org/hardhat-runner/docs/errors#HH700 + if (HardhatError.isHardhatError(e) && e.number === 700 && suffix !== '') { + continue; + } else { + throw e; + } + } + } + throw new Error('Unreachable'); + }; +}); diff --git a/hardhat/task-test-get-files.js b/hardhat/task-test-get-files.js new file mode 100644 index 000000000..896bf1274 --- /dev/null +++ b/hardhat/task-test-get-files.js @@ -0,0 +1,35 @@ +const { internalTask } = require('hardhat/config'); +const { TASK_TEST_GET_TEST_FILES } = require('hardhat/builtin-tasks/task-names'); + +// Modifies `hardhat test` to skip the proxy tests after proxies are removed by the transpiler for upgradeability. + +internalTask(TASK_TEST_GET_TEST_FILES).setAction(async ({ testFiles }, { config }) => { + if (testFiles.length !== 0) { + return testFiles; + } + + const globAsync = require('glob'); + const path = require('path'); + const { promises: fs } = require('fs'); + const { promisify } = require('util'); + + const glob = promisify(globAsync); + + const hasProxies = await fs + .access(path.join(config.paths.sources, 'proxy/Proxy.sol')) + .then(() => true) + .catch(() => false); + + return await glob(path.join(config.paths.tests, '**/*.js'), { + ignore: hasProxies + ? [] + : [ + 'proxy/beacon/BeaconProxy.test.js', + 'proxy/beacon/UpgradeableBeacon.test.js', + 'proxy/ERC1967/ERC1967Proxy.test.js', + 'proxy/transparent/ProxyAdmin.test.js', + 'proxy/transparent/TransparentUpgradeableProxy.test.js', + 'proxy/utils/UUPSUpgradeable.test.js', + ].map(p => path.join(config.paths.tests, p)), + }); +}); diff --git a/package-lock.json b/package-lock.json index 2219b08f2..6611223fe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,7 +31,7 @@ "glob": "^8.0.3", "graphlib": "^2.1.8", "hardhat": "^2.9.1", - "hardhat-exposed": "^0.3.2", + "hardhat-exposed": "^0.3.3", "hardhat-gas-reporter": "^1.0.4", "hardhat-ignore-warnings": "^0.2.0", "keccak256": "^1.0.2", @@ -8269,9 +8269,9 @@ } }, "node_modules/hardhat-exposed": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/hardhat-exposed/-/hardhat-exposed-0.3.2.tgz", - "integrity": "sha512-qhi60I2bfjoPZwKgrY7BIpuUiBE7aC/bHN2MzHxPcZdxaeFnjKJ50n59LE7yK3GK2qYzE8DMjzqfnH6SlKPUjw==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/hardhat-exposed/-/hardhat-exposed-0.3.3.tgz", + "integrity": "sha512-AFBM3IUlSU9wkt3886kYbCSzZteB4OQt0ciehPUrCgY/Tazn6g2cxsmoIZT8O8va1R2PtXd9PRC4KZ6WiSVXOw==", "dev": true, "dependencies": { "micromatch": "^4.0.4", @@ -22857,9 +22857,9 @@ } }, "hardhat-exposed": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/hardhat-exposed/-/hardhat-exposed-0.3.2.tgz", - "integrity": "sha512-qhi60I2bfjoPZwKgrY7BIpuUiBE7aC/bHN2MzHxPcZdxaeFnjKJ50n59LE7yK3GK2qYzE8DMjzqfnH6SlKPUjw==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/hardhat-exposed/-/hardhat-exposed-0.3.3.tgz", + "integrity": "sha512-AFBM3IUlSU9wkt3886kYbCSzZteB4OQt0ciehPUrCgY/Tazn6g2cxsmoIZT8O8va1R2PtXd9PRC4KZ6WiSVXOw==", "dev": true, "requires": { "micromatch": "^4.0.4", diff --git a/package.json b/package.json index a3b98fe37..8ef2738b5 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "glob": "^8.0.3", "graphlib": "^2.1.8", "hardhat": "^2.9.1", - "hardhat-exposed": "^0.3.2", + "hardhat-exposed": "^0.3.3", "hardhat-gas-reporter": "^1.0.4", "hardhat-ignore-warnings": "^0.2.0", "keccak256": "^1.0.2", diff --git a/scripts/upgradeable/README.md b/scripts/upgradeable/README.md new file mode 100644 index 000000000..2309f9e10 --- /dev/null +++ b/scripts/upgradeable/README.md @@ -0,0 +1,21 @@ +The upgradeable variant of OpenZeppelin Contracts is automatically generated from the original Solidity code. We call this process "transpilation" and it is implemented by our [Upgradeability Transpiler](https://github.com/OpenZeppelin/openzeppelin-transpiler/). + +When the `master` branch or `release-v*` branches are updated, the code is transpiled and pushed to [OpenZeppelin/openzeppelin-contracts-upgradeable](https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable) by the `upgradeable.yml` workflow. + +## `transpile.sh` + +Applies patches and invokes the transpiler with the command line flags we need for our requirements (for example, excluding certain files). + +## `transpile-onto.sh` + +``` +bash scripts/upgradeable/transpile-onto.sh [] +``` + +Transpiles the contents of the current git branch and commits the result as a new commit on branch ``. If branch `` doesn't exist, it will copy the commit history of `[]` (this is used in GitHub Actions, but is usually not necessary locally). + +## `patch-apply.sh` & `patch-save.sh` + +Some of the upgradeable contract variants require ad-hoc changes that are not implemented by the transpiler. These changes are implemented by patches stored in `upgradeable.patch` in this directory. `patch-apply.sh` applies these patches. + +If the patches fail to apply due to changes in the repo, the conflicts have to be resolved manually. Once fixed, `patch-save.sh` will take the changes staged in Git and update `upgradeable.patch` to match. diff --git a/scripts/upgradeable/patch-apply.sh b/scripts/upgradeable/patch-apply.sh new file mode 100755 index 000000000..d9e17589b --- /dev/null +++ b/scripts/upgradeable/patch-apply.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +set -euo pipefail + +DIRNAME="$(dirname -- "${BASH_SOURCE[0]}")" +PATCH="$DIRNAME/upgradeable.patch" + +error() { + echo Error: "$*" >&2 + exit 1 +} + +if ! git diff-files --quiet ":!$PATCH" || ! git diff-index --quiet HEAD ":!$PATCH"; then + error "Repository must have no staged or unstaged changes" +fi + +if ! git apply -3 "$PATCH"; then + error "Fix conflicts and run $DIRNAME/patch-save.sh" +fi diff --git a/scripts/upgradeable/patch-save.sh b/scripts/upgradeable/patch-save.sh new file mode 100755 index 000000000..111e6f157 --- /dev/null +++ b/scripts/upgradeable/patch-save.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +set -euo pipefail + +DIRNAME="$(dirname -- "${BASH_SOURCE[0]}")" +PATCH="$DIRNAME/upgradeable.patch" + +error() { + echo Error: "$*" >&2 + exit 1 +} + +if ! git diff-files --quiet ":!$PATCH"; then + error "Unstaged changes. Stage to include in patch or temporarily stash." +fi + +git diff-index --cached --patch --output="$PATCH" HEAD +git restore --staged --worktree ":!$PATCH" diff --git a/scripts/upgradeable/transpile-onto.sh b/scripts/upgradeable/transpile-onto.sh new file mode 100644 index 000000000..a966a9b9a --- /dev/null +++ b/scripts/upgradeable/transpile-onto.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash + +set -euo pipefail + +if [ $# -lt 1 ]; then + echo "usage: bash $0 []" >&2 + exit 1 +fi + +set -x + +target="$1" +base="${2-}" + +bash scripts/upgradeable/transpile.sh + +commit="$(git rev-parse --short HEAD)" +branch="$(git rev-parse --abbrev-ref HEAD)" + +git add contracts + +# detach from the current branch to avoid making changes to it +git checkout --quiet --detach + +# switch to the target branch, creating it if necessary +if git rev-parse -q --verify "$target"; then + # if the branch exists, make it the current HEAD without checking out its contents + git reset --soft "$target" + git checkout "$target" +else + # if the branch doesn't exist, create it as an orphan and check it out + git checkout --orphan "$target" + if [ -n "$base" ] && git rev-parse -q --verify "$base"; then + # if base was specified and it exists, set it as the branch history + git reset --soft "$base" + fi +fi + +# commit if there are changes to commit +if ! git diff --quiet --cached; then + git commit -m "Transpile $commit" +fi + +git checkout "$branch" diff --git a/scripts/upgradeable/transpile.sh b/scripts/upgradeable/transpile.sh new file mode 100644 index 000000000..e3aa31cc0 --- /dev/null +++ b/scripts/upgradeable/transpile.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash + +set -euo pipefail -x + +DIRNAME="$(dirname -- "${BASH_SOURCE[0]}")" + +bash "$DIRNAME/patch-apply.sh" + +npm run clean +npm run compile + +build_info=($(jq -r '.input.sources | keys | if any(test("^contracts/mocks/.*\\bunreachable\\b")) then empty else input_filename end' artifacts/build-info/*)) +build_info_num=${#build_info[@]} + +if [ $build_info_num -ne 1 ]; then + echo "found $build_info_num relevant build info files but expected just 1" + exit 1 +fi + +# -D: delete original and excluded files +# -b: use this build info file +# -i: use included Initializable +# -x: exclude proxy-related contracts with a few exceptions +# -p: emit public initializer +npx @openzeppelin/upgrade-safe-transpiler@latest -D \ + -b "$build_info" \ + -i contracts/proxy/utils/Initializable.sol \ + -x 'contracts-exposed/**/*' \ + -x 'contracts/proxy/**/*' \ + -x '!contracts/proxy/Clones.sol' \ + -x '!contracts/proxy/ERC1967/ERC1967Storage.sol' \ + -x '!contracts/proxy/ERC1967/ERC1967Upgrade.sol' \ + -x '!contracts/proxy/utils/UUPSUpgradeable.sol' \ + -x '!contracts/proxy/beacon/IBeacon.sol' \ + -p 'contracts/**/presets/**/*' diff --git a/scripts/upgradeable/upgradeable.patch b/scripts/upgradeable/upgradeable.patch new file mode 100644 index 000000000..e1988c8e9 --- /dev/null +++ b/scripts/upgradeable/upgradeable.patch @@ -0,0 +1,481 @@ +diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md +deleted file mode 100644 +index 2797a088..00000000 +--- a/.github/ISSUE_TEMPLATE/bug_report.md ++++ /dev/null +@@ -1,21 +0,0 @@ +---- +-name: Bug report +-about: Report a bug in OpenZeppelin Contracts +- +---- +- +- +- +- +- +-**💻 Environment** +- +- +- +-**📝 Details** +- +- +- +-**🔢 Code to reproduce bug** +- +- +diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml +index 4018cef2..d343a53d 100644 +--- a/.github/ISSUE_TEMPLATE/config.yml ++++ b/.github/ISSUE_TEMPLATE/config.yml +@@ -1,4 +1,8 @@ ++blank_issues_enabled: false + contact_links: ++ - name: Bug Reports & Feature Requests ++ url: https://github.com/OpenZeppelin/openzeppelin-contracts/issues/new/choose ++ about: Visit the OpenZeppelin Contracts repository + - name: Questions & Support Requests + url: https://forum.openzeppelin.com/c/support/contracts/18 + about: Ask in the OpenZeppelin Forum +diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md +deleted file mode 100644 +index ff596b0c..00000000 +--- a/.github/ISSUE_TEMPLATE/feature_request.md ++++ /dev/null +@@ -1,14 +0,0 @@ +---- +-name: Feature request +-about: Suggest an idea for OpenZeppelin Contracts +- +---- +- +-**🧐 Motivation** +- +- +-**📝 Details** +- +- +- +- +diff --git a/README.md b/README.md +index 9fc95518..53130e3c 100644 +--- a/README.md ++++ b/README.md +@@ -16,17 +16,20 @@ + + :building_construction: **Want to scale your decentralized application?** Check out [OpenZeppelin Defender](https://openzeppelin.com/defender) — a secure platform for automating and monitoring your operations. + ++> **Note** ++> You are looking at the upgradeable variant of OpenZeppelin Contracts. Be sure to review the documentation on [Using OpenZeppelin Contracts with Upgrades](https://docs.openzeppelin.com/contracts/4.x/upgradeable). ++ + ## Overview + + ### Installation + + ``` +-$ npm install @openzeppelin/contracts ++$ npm install @openzeppelin/contracts-upgradeable + ``` + + OpenZeppelin Contracts features a [stable API](https://docs.openzeppelin.com/contracts/releases-stability#api-stability), which means that your contracts won't break unexpectedly when upgrading to a newer minor version. + +-An alternative to npm is to use the GitHub repository (`openzeppelin/openzeppelin-contracts`) to retrieve the contracts. When doing this, make sure to specify the tag for a release such as `v4.5.0`, instead of using the `master` branch. ++An alternative to npm is to use the GitHub repository (`openzeppelin/openzeppelin-contracts-upgradeable`) to retrieve the contracts. When doing this, make sure to specify the tag for a release such as `v4.5.0`, instead of using the `master` branch. + + ### Usage + +@@ -35,10 +38,11 @@ Once installed, you can use the contracts in the library by importing them: + ```solidity + pragma solidity ^0.8.0; + +-import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; ++import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; + +-contract MyCollectible is ERC721 { +- constructor() ERC721("MyCollectible", "MCO") { ++contract MyCollectible is ERC721Upgradeable { ++ function initialize() initializer public { ++ __ERC721_init("MyCollectible", "MCO"); + } + } + ``` +diff --git a/contracts/finance/VestingWallet.sol b/contracts/finance/VestingWallet.sol +index fe67eb54..d26ea4e1 100644 +--- a/contracts/finance/VestingWallet.sol ++++ b/contracts/finance/VestingWallet.sol +@@ -15,6 +15,8 @@ import "../utils/Context.sol"; + * Any token transferred to this contract will follow the vesting schedule as if they were locked from the beginning. + * Consequently, if the vesting has already started, any amount of tokens sent to this contract will (at least partly) + * be immediately releasable. ++ * ++ * @custom:storage-size 52 + */ + contract VestingWallet is Context { + event EtherReleased(uint256 amount); +diff --git a/contracts/governance/TimelockControllerWith46Migration.sol b/contracts/governance/TimelockControllerWith46Migration.sol +new file mode 100644 +index 00000000..3315e7bd +--- /dev/null ++++ b/contracts/governance/TimelockControllerWith46Migration.sol +@@ -0,0 +1,39 @@ ++// SPDX-License-Identifier: MIT ++// OpenZeppelin Contracts v4.6.0 (governance/TimelockControllerWith46Migration.sol) ++ ++pragma solidity ^0.8.0; ++ ++import "./TimelockController.sol"; ++ ++/** ++ * @dev Extension of the TimelockController that includes an additional ++ * function to migrate from OpenZeppelin Upgradeable Contracts <4.6 to >=4.6. ++ * ++ * This migration is necessary to setup administration rights over the new ++ * `CANCELLER_ROLE`. ++ * ++ * The migration is trustless and can be performed by anyone. ++ * ++ * _Available since v4.6._ ++ */ ++contract TimelockControllerWith46Migration is TimelockController { ++ constructor( ++ uint256 minDelay, ++ address[] memory proposers, ++ address[] memory executors, ++ address admin ++ ) TimelockController(minDelay, proposers, executors, admin) {} ++ ++ /** ++ * @dev Migration function. Running it is necessary for upgradeable ++ * instances that were initially setup with code <4.6 and that upgraded ++ * to >=4.6. ++ */ ++ function migrateTo46() public virtual { ++ require( ++ getRoleAdmin(PROPOSER_ROLE) == TIMELOCK_ADMIN_ROLE && getRoleAdmin(CANCELLER_ROLE) == DEFAULT_ADMIN_ROLE, ++ "TimelockController: already migrated" ++ ); ++ _setRoleAdmin(CANCELLER_ROLE, TIMELOCK_ADMIN_ROLE); ++ } ++} +diff --git a/contracts/governance/extensions/GovernorVotes.sol b/contracts/governance/extensions/GovernorVotes.sol +index 64431711..885f0e42 100644 +--- a/contracts/governance/extensions/GovernorVotes.sol ++++ b/contracts/governance/extensions/GovernorVotes.sol +@@ -10,6 +10,8 @@ import "../../interfaces/IERC5805.sol"; + * @dev Extension of {Governor} for voting weight extraction from an {ERC20Votes} token, or since v4.5 an {ERC721Votes} token. + * + * _Available since v4.3._ ++ * ++ * @custom:storage-size 51 + */ + abstract contract GovernorVotes is Governor { + IERC5805 public immutable token; +diff --git a/contracts/governance/extensions/GovernorVotesComp.sol b/contracts/governance/extensions/GovernorVotesComp.sol +index 17250ad7..1d26b72e 100644 +--- a/contracts/governance/extensions/GovernorVotesComp.sol ++++ b/contracts/governance/extensions/GovernorVotesComp.sol +@@ -10,6 +10,8 @@ import "../../token/ERC20/extensions/ERC20VotesComp.sol"; + * @dev Extension of {Governor} for voting weight extraction from a Comp token. + * + * _Available since v4.3._ ++ * ++ * @custom:storage-size 51 + */ + abstract contract GovernorVotesComp is Governor { + ERC20VotesComp public immutable token; +diff --git a/contracts/package.json b/contracts/package.json +index 55e70b17..ceefb984 100644 +--- a/contracts/package.json ++++ b/contracts/package.json +@@ -1,5 +1,5 @@ + { +- "name": "@openzeppelin/contracts", ++ "name": "@openzeppelin/contracts-upgradeable", + "description": "Secure Smart Contract library for Solidity", + "version": "4.8.2", + "files": [ +@@ -13,7 +13,7 @@ + }, + "repository": { + "type": "git", +- "url": "https://github.com/OpenZeppelin/openzeppelin-contracts.git" ++ "url": "https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable.git" + }, + "keywords": [ + "solidity", +diff --git a/contracts/security/PullPayment.sol b/contracts/security/PullPayment.sol +index 65b4980f..f336592e 100644 +--- a/contracts/security/PullPayment.sol ++++ b/contracts/security/PullPayment.sol +@@ -22,6 +22,8 @@ import "../utils/escrow/Escrow.sol"; + * To use, derive from the `PullPayment` contract, and use {_asyncTransfer} + * instead of Solidity's `transfer` function. Payees can query their due + * payments with {payments}, and retrieve them with {withdrawPayments}. ++ * ++ * @custom:storage-size 51 + */ + abstract contract PullPayment { + Escrow private immutable _escrow; +diff --git a/contracts/token/ERC20/extensions/ERC20Capped.sol b/contracts/token/ERC20/extensions/ERC20Capped.sol +index 16f830d1..9ef98148 100644 +--- a/contracts/token/ERC20/extensions/ERC20Capped.sol ++++ b/contracts/token/ERC20/extensions/ERC20Capped.sol +@@ -7,6 +7,8 @@ import "../ERC20.sol"; + + /** + * @dev Extension of {ERC20} that adds a cap to the supply of tokens. ++ * ++ * @custom:storage-size 51 + */ + abstract contract ERC20Capped is ERC20 { + uint256 private immutable _cap; +diff --git a/contracts/token/ERC20/extensions/ERC20Permit.sol b/contracts/token/ERC20/extensions/ERC20Permit.sol +index a357199b..9dc8e894 100644 +--- a/contracts/token/ERC20/extensions/ERC20Permit.sol ++++ b/contracts/token/ERC20/extensions/ERC20Permit.sol +@@ -18,6 +18,8 @@ import "../../../utils/Counters.sol"; + * need to send a transaction, and thus is not required to hold Ether at all. + * + * _Available since v3.4._ ++ * ++ * @custom:storage-size 51 + */ + abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 { + using Counters for Counters.Counter; +diff --git a/contracts/token/ERC20/extensions/ERC20Wrapper.sol b/contracts/token/ERC20/extensions/ERC20Wrapper.sol +index bfe782e4..7264fe32 100644 +--- a/contracts/token/ERC20/extensions/ERC20Wrapper.sol ++++ b/contracts/token/ERC20/extensions/ERC20Wrapper.sol +@@ -14,6 +14,8 @@ import "../utils/SafeERC20.sol"; + * wrapping of an existing "basic" ERC20 into a governance token. + * + * _Available since v4.2._ ++ * ++ * @custom:storage-size 51 + */ + abstract contract ERC20Wrapper is ERC20 { + IERC20 private immutable _underlying; +diff --git a/contracts/token/ERC20/utils/TokenTimelock.sol b/contracts/token/ERC20/utils/TokenTimelock.sol +index ed855b7b..3d30f59d 100644 +--- a/contracts/token/ERC20/utils/TokenTimelock.sol ++++ b/contracts/token/ERC20/utils/TokenTimelock.sol +@@ -11,6 +11,8 @@ import "./SafeERC20.sol"; + * + * Useful for simple vesting schedules like "advisors get all of their tokens + * after 1 year". ++ * ++ * @custom:storage-size 53 + */ + contract TokenTimelock { + using SafeERC20 for IERC20; +diff --git a/contracts/utils/cryptography/EIP712.sol b/contracts/utils/cryptography/EIP712.sol +index 6a4e1cad..55d8eced 100644 +--- a/contracts/utils/cryptography/EIP712.sol ++++ b/contracts/utils/cryptography/EIP712.sol +@@ -4,7 +4,6 @@ + pragma solidity ^0.8.8; + + import "./ECDSA.sol"; +-import "../ShortStrings.sol"; + import "../../interfaces/IERC5267.sol"; + + /** +@@ -30,27 +29,19 @@ import "../../interfaces/IERC5267.sol"; + * + * _Available since v3.4._ + * +- * @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment ++ * @custom:storage-size 52 + */ + abstract contract EIP712 is IERC5267 { +- using ShortStrings for *; +- + bytes32 private constant _TYPE_HASH = + keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); + +- // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to +- // invalidate the cached domain separator if the chain id changes. +- bytes32 private immutable _cachedDomainSeparator; +- uint256 private immutable _cachedChainId; +- address private immutable _cachedThis; +- ++ /// @custom:oz-renamed-from _HASHED_NAME + bytes32 private immutable _hashedName; ++ /// @custom:oz-renamed-from _HASHED_VERSION + bytes32 private immutable _hashedVersion; + +- ShortString private immutable _name; +- ShortString private immutable _version; +- string private _nameFallback; +- string private _versionFallback; ++ string private _name; ++ string private _version; + + /** + * @dev Initializes the domain separator and parameter caches. +@@ -65,29 +56,23 @@ abstract contract EIP712 is IERC5267 { + * contract upgrade]. + */ + constructor(string memory name, string memory version) { +- _name = name.toShortStringWithFallback(_nameFallback); +- _version = version.toShortStringWithFallback(_versionFallback); +- _hashedName = keccak256(bytes(name)); +- _hashedVersion = keccak256(bytes(version)); +- +- _cachedChainId = block.chainid; +- _cachedDomainSeparator = _buildDomainSeparator(); +- _cachedThis = address(this); ++ _name = name; ++ _version = version; ++ ++ // Reset prior values in storage if upgrading ++ _hashedName = 0; ++ _hashedVersion = 0; + } + + /** + * @dev Returns the domain separator for the current chain. + */ + function _domainSeparatorV4() internal view returns (bytes32) { +- if (address(this) == _cachedThis && block.chainid == _cachedChainId) { +- return _cachedDomainSeparator; +- } else { +- return _buildDomainSeparator(); +- } ++ return _buildDomainSeparator(); + } + + function _buildDomainSeparator() private view returns (bytes32) { +- return keccak256(abi.encode(_TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this))); ++ return keccak256(abi.encode(_TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash(), block.chainid, address(this))); + } + + /** +@@ -129,14 +114,80 @@ abstract contract EIP712 is IERC5267 { + uint256[] memory extensions + ) + { ++ // If the hashed name and version in storage are non-zero, the contract hasn't been properly initialized ++ // and the EIP712 domain is not reliable, as it will be missing name and version. ++ require(_hashedName == 0 && _hashedVersion == 0, "EIP712: Uninitialized"); ++ + return ( + hex"0f", // 01111 +- _name.toStringWithFallback(_nameFallback), +- _version.toStringWithFallback(_versionFallback), ++ _EIP712Name(), ++ _EIP712Version(), + block.chainid, + address(this), + bytes32(0), + new uint256[](0) + ); + } ++ ++ /** ++ * @dev The name parameter for the EIP712 domain. ++ * ++ * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs ++ * are a concern. ++ */ ++ function _EIP712Name() internal virtual view returns (string memory) { ++ return _name; ++ } ++ ++ /** ++ * @dev The version parameter for the EIP712 domain. ++ * ++ * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs ++ * are a concern. ++ */ ++ function _EIP712Version() internal virtual view returns (string memory) { ++ return _version; ++ } ++ ++ /** ++ * @dev The hash of the name parameter for the EIP712 domain. ++ * ++ * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Name` instead. ++ */ ++ function _EIP712NameHash() internal view returns (bytes32) { ++ string memory name = _EIP712Name(); ++ if (bytes(name).length > 0) { ++ return keccak256(bytes(name)); ++ } else { ++ // If the name is empty, the contract may have been upgraded without initializing the new storage. ++ // We return the name hash in storage if non-zero, otherwise we assume the name is empty by design. ++ bytes32 hashedName = _hashedName; ++ if (hashedName != 0) { ++ return hashedName; ++ } else { ++ return keccak256(""); ++ } ++ } ++ } ++ ++ /** ++ * @dev The hash of the version parameter for the EIP712 domain. ++ * ++ * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Version` instead. ++ */ ++ function _EIP712VersionHash() internal view returns (bytes32) { ++ string memory version = _EIP712Version(); ++ if (bytes(version).length > 0) { ++ return keccak256(bytes(version)); ++ } else { ++ // If the version is empty, the contract may have been upgraded without initializing the new storage. ++ // We return the version hash in storage if non-zero, otherwise we assume the version is empty by design. ++ bytes32 hashedVersion = _hashedVersion; ++ if (hashedVersion != 0) { ++ return hashedVersion; ++ } else { ++ return keccak256(""); ++ } ++ } ++ } + } +diff --git a/package.json b/package.json +index 8458dd61..b4672240 100644 +--- a/package.json ++++ b/package.json +@@ -36,7 +36,7 @@ + }, + "repository": { + "type": "git", +- "url": "https://github.com/OpenZeppelin/openzeppelin-contracts.git" ++ "url": "https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable.git" + }, + "keywords": [ + "solidity", +diff --git a/test/utils/cryptography/EIP712.test.js b/test/utils/cryptography/EIP712.test.js +index 54a4e772..ba4602ed 100644 +--- a/test/utils/cryptography/EIP712.test.js ++++ b/test/utils/cryptography/EIP712.test.js +@@ -47,26 +47,6 @@ contract('EIP712', function (accounts) { + const rebuildDomain = await getDomain(this.eip712); + expect(mapValues(rebuildDomain, String)).to.be.deep.equal(mapValues(this.domain, String)); + }); +- +- if (shortOrLong === 'short') { +- // Long strings are in storage, and the proxy will not be properly initialized unless +- // the upgradeable contract variant is used and the initializer is invoked. +- +- it('adjusts when behind proxy', async function () { +- const factory = await Clones.new(); +- const cloneReceipt = await factory.$clone(this.eip712.address); +- const cloneAddress = cloneReceipt.logs.find(({ event }) => event === 'return$clone').args.instance; +- const clone = new EIP712Verifier(cloneAddress); +- +- const cloneDomain = { ...this.domain, verifyingContract: clone.address }; +- +- const reportedDomain = await getDomain(clone); +- expect(mapValues(reportedDomain, String)).to.be.deep.equal(mapValues(cloneDomain, String)); +- +- const expectedSeparator = await domainSeparator(cloneDomain); +- expect(await clone.$_domainSeparatorV4()).to.equal(expectedSeparator); +- }); +- } + }); + + it('hash digest', async function () { diff --git a/test/migrate-imports.test.js b/test/migrate-imports.test.js index 7ec9a97ab..5a5c37a23 100644 --- a/test/migrate-imports.test.js +++ b/test/migrate-imports.test.js @@ -13,6 +13,7 @@ describe('migrate-imports.js', function () { try { await fs.access(path.join('contracts', p), F_OK); } catch (e) { + if (p.startsWith('proxy/')) continue; // excluded from transpilation of upgradeable contracts await fs.access(path.join('contracts', getUpgradeablePath(p)), F_OK); } } diff --git a/test/utils/Checkpoints.test.js b/test/utils/Checkpoints.test.js index 48a00e31a..f395663be 100644 --- a/test/utils/Checkpoints.test.js +++ b/test/utils/Checkpoints.test.js @@ -6,28 +6,48 @@ const { batchInBlock } = require('../helpers/txpool'); const $Checkpoints = artifacts.require('$Checkpoints'); +// The library name may be 'Checkpoints' or 'CheckpointsUpgradeable' +const libraryName = $Checkpoints._json.contractName.replace(/^\$/, ''); + +const traceLengths = [160, 224]; + const first = array => (array.length ? array[0] : undefined); const last = array => (array.length ? array[array.length - 1] : undefined); contract('Checkpoints', function () { beforeEach(async function () { this.mock = await $Checkpoints.new(); + + this.methods = { trace: {} }; + this.methods.history = { + latest: (...args) => this.mock.methods[`$latest_${libraryName}_History(uint256)`](0, ...args), + latestCheckpoint: (...args) => this.mock.methods[`$latestCheckpoint_${libraryName}_History(uint256)`](0, ...args), + length: (...args) => this.mock.methods[`$length_${libraryName}_History(uint256)`](0, ...args), + push: (...args) => this.mock.methods['$push(uint256,uint256)'](0, ...args), + getAtBlock: (...args) => this.mock.$getAtBlock(0, ...args), + getAtRecentBlock: (...args) => this.mock.$getAtProbablyRecentBlock(0, ...args), + }; + for (const length of traceLengths) { + this.methods.trace[length] = { + latest: (...args) => this.mock.methods[`$latest_${libraryName}_Trace${length}(uint256)`](0, ...args), + latestCheckpoint: (...args) => + this.mock.methods[`$latestCheckpoint_${libraryName}_Trace${length}(uint256)`](0, ...args), + length: (...args) => this.mock.methods[`$length_${libraryName}_Trace${length}(uint256)`](0, ...args), + push: (...args) => this.mock.methods[`$push(uint256,uint${256 - length},uint${length})`](0, ...args), + lowerLookup: (...args) => this.mock.methods[`$lowerLookup(uint256,uint${256 - length})`](0, ...args), + upperLookup: (...args) => this.mock.methods[`$upperLookup(uint256,uint${256 - length})`](0, ...args), + upperLookupRecent: (...args) => + this.mock.methods[`$upperLookupRecent(uint256,uint${256 - length})`](0, ...args), + }; + } }); describe('History checkpoints', function () { - const latest = (self, ...args) => self.methods['$latest_Checkpoints_History(uint256)'](0, ...args); - const latestCheckpoint = (self, ...args) => - self.methods['$latestCheckpoint_Checkpoints_History(uint256)'](0, ...args); - const push = (self, ...args) => self.methods['$push(uint256,uint256)'](0, ...args); - const getAtBlock = (self, ...args) => self.methods['$getAtBlock(uint256,uint256)'](0, ...args); - const getAtRecentBlock = (self, ...args) => self.methods['$getAtProbablyRecentBlock(uint256,uint256)'](0, ...args); - const getLength = (self, ...args) => self.methods['$length_Checkpoints_History(uint256)'](0, ...args); - describe('without checkpoints', function () { it('returns zero as latest value', async function () { - expect(await latest(this.mock)).to.be.bignumber.equal('0'); + expect(await this.methods.history.latest()).to.be.bignumber.equal('0'); - const ckpt = await latestCheckpoint(this.mock); + const ckpt = await this.methods.history.latestCheckpoint(); expect(ckpt[0]).to.be.equal(false); expect(ckpt[1]).to.be.bignumber.equal('0'); expect(ckpt[2]).to.be.bignumber.equal('0'); @@ -35,49 +55,63 @@ contract('Checkpoints', function () { it('returns zero as past value', async function () { await time.advanceBlock(); - expect(await getAtBlock(this.mock, (await web3.eth.getBlockNumber()) - 1)).to.be.bignumber.equal('0'); - expect(await getAtRecentBlock(this.mock, (await web3.eth.getBlockNumber()) - 1)).to.be.bignumber.equal('0'); + expect(await this.methods.history.getAtBlock((await web3.eth.getBlockNumber()) - 1)).to.be.bignumber.equal('0'); + expect( + await this.methods.history.getAtRecentBlock((await web3.eth.getBlockNumber()) - 1), + ).to.be.bignumber.equal('0'); }); }); describe('with checkpoints', function () { beforeEach('pushing checkpoints', async function () { - this.tx1 = await push(this.mock, 1); - this.tx2 = await push(this.mock, 2); + this.tx1 = await this.methods.history.push(1); + this.tx2 = await this.methods.history.push(2); await time.advanceBlock(); - this.tx3 = await push(this.mock, 3); + this.tx3 = await this.methods.history.push(3); await time.advanceBlock(); await time.advanceBlock(); }); it('returns latest value', async function () { - expect(await latest(this.mock)).to.be.bignumber.equal('3'); + expect(await this.methods.history.latest()).to.be.bignumber.equal('3'); - const ckpt = await latestCheckpoint(this.mock); + const ckpt = await this.methods.history.latestCheckpoint(); expect(ckpt[0]).to.be.equal(true); expect(ckpt[1]).to.be.bignumber.equal(web3.utils.toBN(this.tx3.receipt.blockNumber)); expect(ckpt[2]).to.be.bignumber.equal(web3.utils.toBN('3')); }); - for (const getAtBlockVariant of [getAtBlock, getAtRecentBlock]) { + for (const getAtBlockVariant of ['getAtBlock', 'getAtRecentBlock']) { describe(`lookup: ${getAtBlockVariant}`, function () { it('returns past values', async function () { - expect(await getAtBlockVariant(this.mock, this.tx1.receipt.blockNumber - 1)).to.be.bignumber.equal('0'); - expect(await getAtBlockVariant(this.mock, this.tx1.receipt.blockNumber)).to.be.bignumber.equal('1'); - expect(await getAtBlockVariant(this.mock, this.tx2.receipt.blockNumber)).to.be.bignumber.equal('2'); + expect( + await this.methods.history[getAtBlockVariant](this.tx1.receipt.blockNumber - 1), + ).to.be.bignumber.equal('0'); + expect(await this.methods.history[getAtBlockVariant](this.tx1.receipt.blockNumber)).to.be.bignumber.equal( + '1', + ); + expect(await this.methods.history[getAtBlockVariant](this.tx2.receipt.blockNumber)).to.be.bignumber.equal( + '2', + ); // Block with no new checkpoints - expect(await getAtBlockVariant(this.mock, this.tx2.receipt.blockNumber + 1)).to.be.bignumber.equal('2'); - expect(await getAtBlockVariant(this.mock, this.tx3.receipt.blockNumber)).to.be.bignumber.equal('3'); - expect(await getAtBlockVariant(this.mock, this.tx3.receipt.blockNumber + 1)).to.be.bignumber.equal('3'); + expect( + await this.methods.history[getAtBlockVariant](this.tx2.receipt.blockNumber + 1), + ).to.be.bignumber.equal('2'); + expect(await this.methods.history[getAtBlockVariant](this.tx3.receipt.blockNumber)).to.be.bignumber.equal( + '3', + ); + expect( + await this.methods.history[getAtBlockVariant](this.tx3.receipt.blockNumber + 1), + ).to.be.bignumber.equal('3'); }); it('reverts if block number >= current block', async function () { await expectRevert( - getAtBlockVariant(this.mock, await web3.eth.getBlockNumber()), + this.methods.history[getAtBlockVariant](await web3.eth.getBlockNumber()), 'Checkpoints: block not yet mined', ); await expectRevert( - getAtBlockVariant(this.mock, (await web3.eth.getBlockNumber()) + 1), + this.methods.history[getAtBlockVariant]((await web3.eth.getBlockNumber()) + 1), 'Checkpoints: block not yet mined', ); }); @@ -85,58 +119,48 @@ contract('Checkpoints', function () { } it('multiple checkpoints in the same block', async function () { - const lengthBefore = await getLength(this.mock); + const lengthBefore = await this.methods.history.length(); await batchInBlock([ - () => push(this.mock, 8, { gas: 100000 }), - () => push(this.mock, 9, { gas: 100000 }), - () => push(this.mock, 10, { gas: 100000 }), + () => this.methods.history.push(8, { gas: 100000 }), + () => this.methods.history.push(9, { gas: 100000 }), + () => this.methods.history.push(10, { gas: 100000 }), ]); - expect(await getLength(this.mock)).to.be.bignumber.equal(lengthBefore.addn(1)); - expect(await latest(this.mock)).to.be.bignumber.equal('10'); + expect(await this.methods.history.length()).to.be.bignumber.equal(lengthBefore.addn(1)); + expect(await this.methods.history.latest()).to.be.bignumber.equal('10'); }); it('more than 5 checkpoints', async function () { for (let i = 4; i <= 6; i++) { - await push(this.mock, i); + await this.methods.history.push(i); } - expect(await getLength(this.mock)).to.be.bignumber.equal('6'); + expect(await this.methods.history.length()).to.be.bignumber.equal('6'); const block = await web3.eth.getBlockNumber(); // recent - expect(await getAtRecentBlock(this.mock, block - 1)).to.be.bignumber.equal('5'); + expect(await this.methods.history.getAtRecentBlock(block - 1)).to.be.bignumber.equal('5'); // non-recent - expect(await getAtRecentBlock(this.mock, block - 9)).to.be.bignumber.equal('0'); + expect(await this.methods.history.getAtRecentBlock(block - 9)).to.be.bignumber.equal('0'); }); }); }); - for (const length of [160, 224]) { + for (const length of traceLengths) { describe(`Trace${length}`, function () { - const latest = (self, ...args) => self.methods[`$latest_Checkpoints_Trace${length}(uint256)`](0, ...args); - const latestCheckpoint = (self, ...args) => - self.methods[`$latestCheckpoint_Checkpoints_Trace${length}(uint256)`](0, ...args); - const push = (self, ...args) => self.methods[`$push(uint256,uint${256 - length},uint${length})`](0, ...args); - const lowerLookup = (self, ...args) => self.methods[`$lowerLookup(uint256,uint${256 - length})`](0, ...args); - const upperLookup = (self, ...args) => self.methods[`$upperLookup(uint256,uint${256 - length})`](0, ...args); - const upperLookupRecent = (self, ...args) => - self.methods[`$upperLookupRecent(uint256,uint${256 - length})`](0, ...args); - const getLength = (self, ...args) => self.methods[`$length_Checkpoints_Trace${length}(uint256)`](0, ...args); - describe('without checkpoints', function () { it('returns zero as latest value', async function () { - expect(await latest(this.mock)).to.be.bignumber.equal('0'); + expect(await this.methods.trace[length].latest()).to.be.bignumber.equal('0'); - const ckpt = await latestCheckpoint(this.mock); + const ckpt = await this.methods.trace[length].latestCheckpoint(); expect(ckpt[0]).to.be.equal(false); expect(ckpt[1]).to.be.bignumber.equal('0'); expect(ckpt[2]).to.be.bignumber.equal('0'); }); it('lookup returns 0', async function () { - expect(await lowerLookup(this.mock, 0)).to.be.bignumber.equal('0'); - expect(await upperLookup(this.mock, 0)).to.be.bignumber.equal('0'); - expect(await upperLookupRecent(this.mock, 0)).to.be.bignumber.equal('0'); + expect(await this.methods.trace[length].lowerLookup(0)).to.be.bignumber.equal('0'); + expect(await this.methods.trace[length].upperLookup(0)).to.be.bignumber.equal('0'); + expect(await this.methods.trace[length].upperLookupRecent(0)).to.be.bignumber.equal('0'); }); }); @@ -150,46 +174,49 @@ contract('Checkpoints', function () { { key: '11', value: '99' }, ]; for (const { key, value } of this.checkpoints) { - await push(this.mock, key, value); + await this.methods.trace[length].push(key, value); } }); it('length', async function () { - expect(await getLength(this.mock)).to.be.bignumber.equal(this.checkpoints.length.toString()); + expect(await this.methods.trace[length].length()).to.be.bignumber.equal(this.checkpoints.length.toString()); }); it('returns latest value', async function () { - expect(await latest(this.mock)).to.be.bignumber.equal(last(this.checkpoints).value); + expect(await this.methods.trace[length].latest()).to.be.bignumber.equal(last(this.checkpoints).value); - const ckpt = await latestCheckpoint(this.mock); + const ckpt = await this.methods.trace[length].latestCheckpoint(); expect(ckpt[0]).to.be.equal(true); expect(ckpt[1]).to.be.bignumber.equal(last(this.checkpoints).key); expect(ckpt[2]).to.be.bignumber.equal(last(this.checkpoints).value); }); it('cannot push values in the past', async function () { - await expectRevert(push(this.mock, last(this.checkpoints).key - 1, '0'), 'Checkpoint: decreasing keys'); + await expectRevert( + this.methods.trace[length].push(last(this.checkpoints).key - 1, '0'), + 'Checkpoint: decreasing keys', + ); }); it('can update last value', async function () { const newValue = '42'; // check length before the update - expect(await getLength(this.mock)).to.be.bignumber.equal(this.checkpoints.length.toString()); + expect(await this.methods.trace[length].length()).to.be.bignumber.equal(this.checkpoints.length.toString()); // update last key - await push(this.mock, last(this.checkpoints).key, newValue); - expect(await latest(this.mock)).to.be.bignumber.equal(newValue); + await this.methods.trace[length].push(last(this.checkpoints).key, newValue); + expect(await this.methods.trace[length].latest()).to.be.bignumber.equal(newValue); // check that length did not change - expect(await getLength(this.mock)).to.be.bignumber.equal(this.checkpoints.length.toString()); + expect(await this.methods.trace[length].length()).to.be.bignumber.equal(this.checkpoints.length.toString()); }); it('lower lookup', async function () { for (let i = 0; i < 14; ++i) { const value = first(this.checkpoints.filter(x => i <= x.key))?.value || '0'; - expect(await lowerLookup(this.mock, i)).to.be.bignumber.equal(value); + expect(await this.methods.trace[length].lowerLookup(i)).to.be.bignumber.equal(value); } }); @@ -197,8 +224,8 @@ contract('Checkpoints', function () { for (let i = 0; i < 14; ++i) { const value = last(this.checkpoints.filter(x => i >= x.key))?.value || '0'; - expect(await upperLookup(this.mock, i)).to.be.bignumber.equal(value); - expect(await upperLookupRecent(this.mock, i)).to.be.bignumber.equal(value); + expect(await this.methods.trace[length].upperLookup(i)).to.be.bignumber.equal(value); + expect(await this.methods.trace[length].upperLookupRecent(i)).to.be.bignumber.equal(value); } }); @@ -213,13 +240,13 @@ contract('Checkpoints', function () { const allCheckpoints = [].concat(this.checkpoints, moreCheckpoints); for (const { key, value } of moreCheckpoints) { - await push(this.mock, key, value); + await this.methods.trace[length].push(key, value); } for (let i = 0; i < 25; ++i) { const value = last(allCheckpoints.filter(x => i >= x.key))?.value || '0'; - expect(await upperLookup(this.mock, i)).to.be.bignumber.equal(value); - expect(await upperLookupRecent(this.mock, i)).to.be.bignumber.equal(value); + expect(await this.methods.trace[length].upperLookup(i)).to.be.bignumber.equal(value); + expect(await this.methods.trace[length].upperLookupRecent(i)).to.be.bignumber.equal(value); } }); }); diff --git a/test/utils/cryptography/EIP712.test.js b/test/utils/cryptography/EIP712.test.js index 52e322d3d..54a4e7723 100644 --- a/test/utils/cryptography/EIP712.test.js +++ b/test/utils/cryptography/EIP712.test.js @@ -60,11 +60,11 @@ contract('EIP712', function (accounts) { const cloneDomain = { ...this.domain, verifyingContract: clone.address }; - const expectedSeparator = await domainSeparator(cloneDomain); - expect(await clone.$_domainSeparatorV4()).to.equal(expectedSeparator); - const reportedDomain = await getDomain(clone); expect(mapValues(reportedDomain, String)).to.be.deep.equal(mapValues(cloneDomain, String)); + + const expectedSeparator = await domainSeparator(cloneDomain); + expect(await clone.$_domainSeparatorV4()).to.equal(expectedSeparator); }); } }); diff --git a/test/utils/structs/EnumerableMap.test.js b/test/utils/structs/EnumerableMap.test.js index 548e73775..f540ec99e 100644 --- a/test/utils/structs/EnumerableMap.test.js +++ b/test/utils/structs/EnumerableMap.test.js @@ -14,6 +14,9 @@ const getMethods = ms => { ); }; +// Get the name of the library. In the transpiled code it will be EnumerableMapUpgradeable. +const library = EnumerableMap._json.contractName.replace(/^\$/, ''); + contract('EnumerableMap', function (accounts) { const [accountA, accountB, accountC] = accounts; @@ -41,14 +44,14 @@ contract('EnumerableMap', function (accounts) { getWithMessage: '$get(uint256,address,string)', tryGet: '$tryGet(uint256,address)', remove: '$remove(uint256,address)', - length: '$length_EnumerableMap_AddressToUintMap(uint256)', - at: '$at_EnumerableMap_AddressToUintMap(uint256,uint256)', + length: `$length_${library}_AddressToUintMap(uint256)`, + at: `$at_${library}_AddressToUintMap(uint256,uint256)`, contains: '$contains(uint256,address)', - keys: '$keys_EnumerableMap_AddressToUintMap(uint256)', + keys: `$keys_${library}_AddressToUintMap(uint256)`, }), { - setReturn: 'return$set_EnumerableMap_AddressToUintMap_address_uint256', - removeReturn: 'return$remove_EnumerableMap_AddressToUintMap_address', + setReturn: `return$set_${library}_AddressToUintMap_address_uint256`, + removeReturn: `return$remove_${library}_AddressToUintMap_address`, }, ); }); @@ -61,18 +64,18 @@ contract('EnumerableMap', function (accounts) { constants.ZERO_ADDRESS, getMethods({ set: '$set(uint256,uint256,address)', - get: '$get_EnumerableMap_UintToAddressMap(uint256,uint256)', - getWithMessage: '$get_EnumerableMap_UintToAddressMap(uint256,uint256,string)', - tryGet: '$tryGet_EnumerableMap_UintToAddressMap(uint256,uint256)', - remove: '$remove_EnumerableMap_UintToAddressMap(uint256,uint256)', - length: '$length_EnumerableMap_UintToAddressMap(uint256)', - at: '$at_EnumerableMap_UintToAddressMap(uint256,uint256)', - contains: '$contains_EnumerableMap_UintToAddressMap(uint256,uint256)', - keys: '$keys_EnumerableMap_UintToAddressMap(uint256)', + get: `$get_${library}_UintToAddressMap(uint256,uint256)`, + getWithMessage: `$get_${library}_UintToAddressMap(uint256,uint256,string)`, + tryGet: `$tryGet_${library}_UintToAddressMap(uint256,uint256)`, + remove: `$remove_${library}_UintToAddressMap(uint256,uint256)`, + length: `$length_${library}_UintToAddressMap(uint256)`, + at: `$at_${library}_UintToAddressMap(uint256,uint256)`, + contains: `$contains_${library}_UintToAddressMap(uint256,uint256)`, + keys: `$keys_${library}_UintToAddressMap(uint256)`, }), { - setReturn: 'return$set_EnumerableMap_UintToAddressMap_uint256_address', - removeReturn: 'return$remove_EnumerableMap_UintToAddressMap_uint256', + setReturn: `return$set_${library}_UintToAddressMap_uint256_address`, + removeReturn: `return$remove_${library}_UintToAddressMap_uint256`, }, ); }); @@ -85,18 +88,18 @@ contract('EnumerableMap', function (accounts) { constants.ZERO_BYTES32, getMethods({ set: '$set(uint256,bytes32,bytes32)', - get: '$get_EnumerableMap_Bytes32ToBytes32Map(uint256,bytes32)', - getWithMessage: '$get_EnumerableMap_Bytes32ToBytes32Map(uint256,bytes32,string)', - tryGet: '$tryGet_EnumerableMap_Bytes32ToBytes32Map(uint256,bytes32)', - remove: '$remove_EnumerableMap_Bytes32ToBytes32Map(uint256,bytes32)', - length: '$length_EnumerableMap_Bytes32ToBytes32Map(uint256)', - at: '$at_EnumerableMap_Bytes32ToBytes32Map(uint256,uint256)', - contains: '$contains_EnumerableMap_Bytes32ToBytes32Map(uint256,bytes32)', - keys: '$keys_EnumerableMap_Bytes32ToBytes32Map(uint256)', + get: `$get_${library}_Bytes32ToBytes32Map(uint256,bytes32)`, + getWithMessage: `$get_${library}_Bytes32ToBytes32Map(uint256,bytes32,string)`, + tryGet: `$tryGet_${library}_Bytes32ToBytes32Map(uint256,bytes32)`, + remove: `$remove_${library}_Bytes32ToBytes32Map(uint256,bytes32)`, + length: `$length_${library}_Bytes32ToBytes32Map(uint256)`, + at: `$at_${library}_Bytes32ToBytes32Map(uint256,uint256)`, + contains: `$contains_${library}_Bytes32ToBytes32Map(uint256,bytes32)`, + keys: `$keys_${library}_Bytes32ToBytes32Map(uint256)`, }), { - setReturn: 'return$set_EnumerableMap_Bytes32ToBytes32Map_bytes32_bytes32', - removeReturn: 'return$remove_EnumerableMap_Bytes32ToBytes32Map_bytes32', + setReturn: `return$set_${library}_Bytes32ToBytes32Map_bytes32_bytes32`, + removeReturn: `return$remove_${library}_Bytes32ToBytes32Map_bytes32`, }, ); }); @@ -109,18 +112,18 @@ contract('EnumerableMap', function (accounts) { new BN('0'), getMethods({ set: '$set(uint256,uint256,uint256)', - get: '$get_EnumerableMap_UintToUintMap(uint256,uint256)', - getWithMessage: '$get_EnumerableMap_UintToUintMap(uint256,uint256,string)', - tryGet: '$tryGet_EnumerableMap_UintToUintMap(uint256,uint256)', - remove: '$remove_EnumerableMap_UintToUintMap(uint256,uint256)', - length: '$length_EnumerableMap_UintToUintMap(uint256)', - at: '$at_EnumerableMap_UintToUintMap(uint256,uint256)', - contains: '$contains_EnumerableMap_UintToUintMap(uint256,uint256)', - keys: '$keys_EnumerableMap_UintToUintMap(uint256)', + get: `$get_${library}_UintToUintMap(uint256,uint256)`, + getWithMessage: `$get_${library}_UintToUintMap(uint256,uint256,string)`, + tryGet: `$tryGet_${library}_UintToUintMap(uint256,uint256)`, + remove: `$remove_${library}_UintToUintMap(uint256,uint256)`, + length: `$length_${library}_UintToUintMap(uint256)`, + at: `$at_${library}_UintToUintMap(uint256,uint256)`, + contains: `$contains_${library}_UintToUintMap(uint256,uint256)`, + keys: `$keys_${library}_UintToUintMap(uint256)`, }), { - setReturn: 'return$set_EnumerableMap_UintToUintMap_uint256_uint256', - removeReturn: 'return$remove_EnumerableMap_UintToUintMap_uint256', + setReturn: `return$set_${library}_UintToUintMap_uint256_uint256`, + removeReturn: `return$remove_${library}_UintToUintMap_uint256`, }, ); }); @@ -133,18 +136,18 @@ contract('EnumerableMap', function (accounts) { new BN('0'), getMethods({ set: '$set(uint256,bytes32,uint256)', - get: '$get_EnumerableMap_Bytes32ToUintMap(uint256,bytes32)', - getWithMessage: '$get_EnumerableMap_Bytes32ToUintMap(uint256,bytes32,string)', - tryGet: '$tryGet_EnumerableMap_Bytes32ToUintMap(uint256,bytes32)', - remove: '$remove_EnumerableMap_Bytes32ToUintMap(uint256,bytes32)', - length: '$length_EnumerableMap_Bytes32ToUintMap(uint256)', - at: '$at_EnumerableMap_Bytes32ToUintMap(uint256,uint256)', - contains: '$contains_EnumerableMap_Bytes32ToUintMap(uint256,bytes32)', - keys: '$keys_EnumerableMap_Bytes32ToUintMap(uint256)', + get: `$get_${library}_Bytes32ToUintMap(uint256,bytes32)`, + getWithMessage: `$get_${library}_Bytes32ToUintMap(uint256,bytes32,string)`, + tryGet: `$tryGet_${library}_Bytes32ToUintMap(uint256,bytes32)`, + remove: `$remove_${library}_Bytes32ToUintMap(uint256,bytes32)`, + length: `$length_${library}_Bytes32ToUintMap(uint256)`, + at: `$at_${library}_Bytes32ToUintMap(uint256,uint256)`, + contains: `$contains_${library}_Bytes32ToUintMap(uint256,bytes32)`, + keys: `$keys_${library}_Bytes32ToUintMap(uint256)`, }), { - setReturn: 'return$set_EnumerableMap_Bytes32ToUintMap_bytes32_uint256', - removeReturn: 'return$remove_EnumerableMap_Bytes32ToUintMap_bytes32', + setReturn: `return$set_${library}_Bytes32ToUintMap_bytes32_uint256`, + removeReturn: `return$remove_${library}_Bytes32ToUintMap_bytes32`, }, ); }); diff --git a/test/utils/structs/EnumerableSet.test.js b/test/utils/structs/EnumerableSet.test.js index 862cb6d9e..3ba9d7ff7 100644 --- a/test/utils/structs/EnumerableSet.test.js +++ b/test/utils/structs/EnumerableSet.test.js @@ -12,6 +12,9 @@ const getMethods = ms => { ); }; +// Get the name of the library. In the transpiled code it will be EnumerableSetUpgradeable. +const library = EnumerableSet._json.contractName.replace(/^\$/, ''); + contract('EnumerableSet', function (accounts) { beforeEach(async function () { this.set = await EnumerableSet.new(); @@ -25,13 +28,13 @@ contract('EnumerableSet', function (accounts) { add: '$add(uint256,bytes32)', remove: '$remove(uint256,bytes32)', contains: '$contains(uint256,bytes32)', - length: '$length_EnumerableSet_Bytes32Set(uint256)', - at: '$at_EnumerableSet_Bytes32Set(uint256,uint256)', - values: '$values_EnumerableSet_Bytes32Set(uint256)', + length: `$length_${library}_Bytes32Set(uint256)`, + at: `$at_${library}_Bytes32Set(uint256,uint256)`, + values: `$values_${library}_Bytes32Set(uint256)`, }), { - addReturn: 'return$add_EnumerableSet_Bytes32Set_bytes32', - removeReturn: 'return$remove_EnumerableSet_Bytes32Set_bytes32', + addReturn: `return$add_${library}_Bytes32Set_bytes32`, + removeReturn: `return$remove_${library}_Bytes32Set_bytes32`, }, ); }); @@ -44,13 +47,13 @@ contract('EnumerableSet', function (accounts) { add: '$add(uint256,address)', remove: '$remove(uint256,address)', contains: '$contains(uint256,address)', - length: '$length_EnumerableSet_AddressSet(uint256)', - at: '$at_EnumerableSet_AddressSet(uint256,uint256)', - values: '$values_EnumerableSet_AddressSet(uint256)', + length: `$length_${library}_AddressSet(uint256)`, + at: `$at_${library}_AddressSet(uint256,uint256)`, + values: `$values_${library}_AddressSet(uint256)`, }), { - addReturn: 'return$add_EnumerableSet_AddressSet_address', - removeReturn: 'return$remove_EnumerableSet_AddressSet_address', + addReturn: `return$add_${library}_AddressSet_address`, + removeReturn: `return$remove_${library}_AddressSet_address`, }, ); }); @@ -63,13 +66,13 @@ contract('EnumerableSet', function (accounts) { add: '$add(uint256,uint256)', remove: '$remove(uint256,uint256)', contains: '$contains(uint256,uint256)', - length: '$length_EnumerableSet_UintSet(uint256)', - at: '$at_EnumerableSet_UintSet(uint256,uint256)', - values: '$values_EnumerableSet_UintSet(uint256)', + length: `$length_${library}_UintSet(uint256)`, + at: `$at_${library}_UintSet(uint256,uint256)`, + values: `$values_${library}_UintSet(uint256)`, }), { - addReturn: 'return$add_EnumerableSet_UintSet_uint256', - removeReturn: 'return$remove_EnumerableSet_UintSet_uint256', + addReturn: `return$add_${library}_UintSet_uint256`, + removeReturn: `return$remove_${library}_UintSet_uint256`, }, ); }); From 0ee84342b72e7874433b47a591d460d3f22ebf8e Mon Sep 17 00:00:00 2001 From: Francisco Date: Tue, 9 May 2023 20:09:52 +0100 Subject: [PATCH 123/133] Add PDF report for v4.9 audit (#4227) --- audits/2023-05-v4.9.pdf | Bin 0 -> 483005 bytes audits/README.md | 1 + 2 files changed, 1 insertion(+) create mode 100644 audits/2023-05-v4.9.pdf diff --git a/audits/2023-05-v4.9.pdf b/audits/2023-05-v4.9.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e7e6d715b04b0fffb92f424b63120a01e2207f72 GIT binary patch literal 483005 zcmdSC2|SeR`v;6vRI;_p)~1feGR9bnMAAv96rzzy!^kXR?0ZLPrA{Fv+lk6r2HABK zC&EbfhRU&I45zGF-}`xHVo1OL>HN*0O- z5sGpu%eMX%9s1icMJWX-^69h7cJG!y=I(%#l0S^K#W~6A+nsTevOojnQ7KjU|H^9c zK@q9KKC-_nvA?4rq@z-bC?)n$nSEsIm04hlXto`iEmuLZ>{MCpkP7T05(UeVY$!GAv=>OQb=V@&1E>!87Nf9Av@&5j^s1W);LG0 z?WQ=allx&uJ7BAUr*Kx#QDc^`^y+h&6Nw^M{f+dh`S&5f|qmegqrT~99Cn*#w9rA`)BKQW1 zv=8S*flpWxi|trzYn+o4!kSE?IFbphBi5SYv_s0`Yc1r>PMAxnD9EXz(TXUfl!}U? zoB~n_jRc9nNU;If?a$zBu+9Vu_6*UEXJHV22}75RP!hac2Oe zlQXM1iq*a5HCI$q0aRw2lS$SDXD2%{3392#>Jn1(+Nc2f=-G6@iGUJ_K&b)81kf*V z2rN{10Kw|RFo2?>lAMyNvMRV9lvP#blvUA+pmrdBoEw(tK)^xyV)ya+4(I0I#+hVI z0TdA~c20Ju?Fe=hcZ4;TggA{uI5?js*jWRluUEx9BqT~v4uw`!RtDD+@cbW;K+-9W zcGeW!neU^iD4^vOXA@ydcELH4uq12TyiUcs;O0>Q(aR~!7S4|7Kz0J*5O4?z8DWc~ zAV5T*t3nqe=oVNC;Dc}>g9CzscO*O8;=vJzVEH6FvNT^y0a0dO_Vc|eAmx-$C?pb$ zQ6K?!Bx^F1dkPM5hHULj1bqh!r536Mdz_gEpaKDK&;|e`Cp#w!)a#tEHaKf6;OXoH z#zcq&drX>#fmQ*XPIaaVUx}|2`T@6)mTxgj8T( zO$4m9J%Vh5up^zpxq&Od0qY2c0^k8i5I7gW6M|w7g7b)>R2AjWC^UKo3W~)6T$=y~ z;)Zp>+7Yl&jhsN{pfVF7rcMaZBk@?0EifZHLX?5p7IMQLi|4t4`i%lw6%7VnPy=>t zIeO1*LcoaNOmcE|fW}W&Ph1!grGl1IQdC5%fx!}jB)cMzkXb79bVBl`>})JzKwtWfNTI0D() zo;`CCKx&{GIXl4<)OQ9fXs%RKRY9^kwgccqqSyg4PGF+32Dc3$y95H52S8$6@i?gZ ztZ^H52nI+;oHfqQ1ve8v)WH_+oJycmBWJ^(aYb+kkz11;0TLLLStBxp4#pTT>OyDE zBs(w$!0w@V9qr&6;~cG3kczB<`4kw?S;j2enQ9=QlsXfz5UqtrY-MG%98!6vD&O{Q z_;vvSKqz)#k06%f9KG*K5&gC^^+xOebry13djAS+|1otmj>|PB?34XkbAQ zLBA%z<08e;8H|)zaIZmhfVv0V$rirhK%rDPZyw-_6ybt(w1bCLju{A_6L)iyh7tDhT@y{Xe&( zz{EjkfVwp_8Gx3o2Y~;fox1}WT(b^%J8=KU8pi%Z#gx<(59uq41$c1T44{gO1i%DMd|9`MvC~I(wn7KwxHc`YgEkArm`Av?}Pr zr_pMsRaI2gtg&jRPor=OD3sc1MP)@5Ya1z)8hoP-njOYcz-FCnGsv505cg7x&8hfp6ht0Y4NbsfQVab?|&(l4PKf7eeZp2%w zx$JJwiRS<5#yP*wr?o3L{vwm<_Tb)6v}d>;n_I!6&(2$;wbSqMxHUO!*=JHcQkT3} zpl9m-K^1MPIv4NCWi{)V3LY*!?#JoJg8LnkllqbO#{7S}{&=F@{lYIp-G?`CK7S-M z3LSJL;FaW~CT7RPhtY#-@h2)9>VkE+%<8*W;?6QQ)!MklX2$OSsV4o9Me;WMF^iqF z^RjL2({*LK8zL@y+8c|Vdb;#+*8MvvI+Mngdy2vZHYKHqKe-uaRMGtW*D?bl!M~ml zal3zYLBy56_WhP{#&ExII{IV`f*GKBD&d986A{P3J(Ws^E47kPWlvAn^Vo~IakVaO zYAx$BRvxdKF7P*k zQAJ^M2z?8wrF%c^T)jTE>G^}?nC(~6ipy^Bh7%oSEy|Zuik~@Defaq0 zW#yL?WK5JnH7$d9=z!r~eg0Pk%M5z-4W<#r7DJ2;BRsp1w>qLPtkRfD3SW~c9V&SW zJ@C1&n?VoJZbqQfQ&6gp_wHQW@P{l#7ICJ$=Zy2?#N}y$L4i-(#oPi5;-^}iCr-4U zt%xqFy{7ybTfOTKv8W@yVIN{L-abL_A5+_Bn~^jSADL8}p>ondF6Po;R7I0>TNJS> zEUJatYHYiOarbN`Gf7r=4c+jlO1r#lSlepoa%6W}_74ouQ{tRQeCRh7aQ!%f@s$05 zZvgHwvD#!eDGTUl3S~8AIi!lRG8nj2!6Th27&p);=%)+T5G(~>g7QakPGo0C@U$-l zUtaRZ9PNnz6NEMahdc8>7|mX%&?WspU#DtnigPa1lqgJaN9nnX{avQ7GP!FBE(6Pj z)?B*r=kMv)*M+_--YaLLC%gXHPkzj+6O+f3UwSZJ^}cf7x#M^BUZra3@f(#k1;^`N zd{%AtEs`7FVQzooa0q!ZUX?VDAb(L8**rA@r0wzlS;?fA$it5oKf zkGd)e=OjbjGc=021H~OPYn-M$Kc(PKEg3IA*25rQC%XSkZb?sVK~-Io)5)-~JtbU_ z^=#MYp4~p-mTMR4m9xs_-2O=O?2lJ>`(>_AJHbCCT(tD=fY8Q`@h|RqbwZqc=Z|5mr?ZOLKZ`yExuEpM(yP${llyDl3(% zI@9iaue4mQ>d!?kk}@dXt`Cb`)-N9qi5D=7+;Jqkh1Bl+V9*ha?SXw*0uMC&a{Z-s-}$jW$tpfr3y6K zHOuCy-x6%}j&7{mp=lLXke*~rC^mGq&Gr%_7DtF{HRg^xWctLnnW;#o+3bIHE$h?S z>cZ8SNI;WL@Y?M0>C@Saog4g}fgIg`ay_%%xotx(I`fMgChJP7K?>S(B=>R9A@oUR zI2vT?i$kWK>;}KO-U4Tp+91r`nu|&6x9!SPjTbbHl%%}~cacm*FR4*`d=;+|UcXvk z?=JCrQPJbF@!rL9vblY=r`zj#e_M~a`%)tLMb&AYwPhql#vi#R^`gc>L_0>n{&!~t zO)@q#Tm}|pj4WhHO9GMcG9OvuDbBEZtfqhZwd$%;--jf@-x)trTu(K$Q(X!nQI3W&j`8H z`GvLhFTG97_-YzJlitU5H-InZ7A%>?2%xcBiEJ8qzjGfSLYk+0%Ra6s*i@Q2(*n4g zF=cy|-q)9L;u6~zbkLH48-K+BQ17;IBF1jr*H_DG0Zg^Kg*I`qf>;29xG2kTxl(>& z&C=dNg_4$JcgD*n;7H(R{EWHto>)I&)nkLb=z7AtI2D)~gq|>JK5uAc;@FShVeBZ` zcFfU+vXUXYwIQ|fbdrf7`TSMM1 zt>o9k!*J5-07ssGY2%i8SOEMhHDGM@v+BM;m?2BPlJ+x;D8MS*ve6%A0zuAN%~D%L z;q)jBJf7EM95`|3J;p{dz2)~6{ja@>t3dW{-SIN23%}##V{s@;y*KUoZ|gs{Pu%`> zRm;s{GmMpwt523>i;bux(Ji~r-qoAnxFBP4Yg!y_`A2Lb4Try ziQNhxVz#RD@0=0F-0I#!-Ph%{+M0htD@tl@vh z3gR0KU>8!p>uB-q^2F?rE11Q`ae3h?h3goCZBu=WHs1lW^7Pi7Ws#au=hAQNko3XS zrv+Uw(RguA^E|GBCuR8bkx)iN;SI*e>laSc*TfoTRMS*2pW}lWvThQkFFMcv-YwGn zS+n4d0XBGYYU8HC-G>s7Z5l+m>Ag+hqE@8m3`GXhT&(*uBLf5OU3|DEdxVRS;U}!W zoZVtHgdu z#99Q~D#aM=+nMOGWf1ws{j39}g^KKJU#6FRBCv(Z1Yd7?WhDvfxu)o3Ht`0LjNe!@ zOnCgfuV~_S#xmY%^8?XA67E?ICN!wH2J@)$^#HG4c6f26gKBQ2< zNR)^Hl$uvd8E7#&u`SU3f{SYlz<$$*wx_JKJ?olH6r2`}t@OC_fX*!3?RzP`hNzBH zxX;r?8ktDB-b}A7K#5WFB0t)R9d+mv_Z&<2EXklEKcl@-!VPq{Osa5OLPx{U@3KtC2huP@1gz8!kg zm$lSkl%Jp2S;EI8DJd-}LJ=r=i5@2&(lPXr!w={fl?(}+v#t%!Vp&nm^n}Mu#Y4=# zT*KjY2`;YAU7%54?wuhTunV)hqjJ{ObOgdo&0xiM_#$H!trF(ZyhdJh2}p)r(Bfu# zX2g(!ab8P2A2Hs=H3g`E0Q;MZYt-(GhRnVmY%@q)U6debVZ*y}SnT~< zOoeLW$;Dly;Eyll$8KN{o&3-1SMxYqwg$urE(;zYwtbIrR zEL_^#e-E7@kzV9!-f%!*6ZM2(W19x>Yvr3w=e>A1&(r*sSIku3%SC-ap3~1gp2u9e za@Vk{k<t3~G3l-J~ z(RLg-(9I_zVzyUXD^W^1b~UW=Gn|3o7vHPRwV(zD50aAhU%e&YsB59N+$pdY^2LGp zFOcf51+=Xe^Ya4-F~%Uixv^1r`T3LQXgFg7`6y=Db4u9}gIw^avVcJ@cquc$thDOE zZF$revfu*=huqF>H`iX`r5W|he_Ot9OThQx;Ev|u zD{^f`>xuR+x+a{%d&bE>@6sVNJ($HlZ&rT#E4)GM$*X62@6HL9 z9R8T(Bw79F`0GhG&L;{ z;Q?}R4ndsney|`6*If=+HrzhF8JGo|jy*EvX*~7~EX0f}s%Lw?ZCoQ}S0OPqT%fRR zV?t4AR>DD&?XSj)6%YHmY`c;Oc`uyJZL!y{XRm3vX*E>-4jr4mD$U{ZqouEMJ?i>h zQ)IO(a(O6EQn{j%Wwm4&S7_|hirh`lM6dh7 z5d8{I`44LxG+{VcUUweG$5SWjX1 zqp|}YYYu8m4Xp@aUb{fZK6j%KQ|~fsYJybYP!T z7YN}$qz?{x4ETI!COij|69*~>NH0{D1ylSV(hH?O0DPeEp>sdO4$V`wO+QbGW_X^o z>h0)@6d`Z?I9~1gTS>g-a(>NLIdpeWzk$By=As7)xOmA-zF7GoucIOL_S_{Cl)P61 zj`?{dlj@e!1fvkEJwN&G2vWLdIBK-iSB;t0u-_)o>sW|*h+y6L2>oMz^r_zL5vI7z zROQ2b#&a3!-O+$hQAyg%%SL#$PyFJBUR*LVnz0?Q#?R2uOS=Nra7O{dl`@+C9nY6i z96yMf!y3WvKfgjm)80Q{>adUo2Jd$GAZlhfF-~z=psgegv@@HJ_%D!})&#V9Lq(&3 zgGK5fKE&ME0!5>X9Y3@sW{i64PK$iV&crsQz1BT6p*iXGX?gIn=V{YdJq}ol1UK}I zul-%AK_l1loJcrsKI0Qk%i^N}m^a@{pH68vBl*`bq*O>9@wAr=HJe^&8tT!`}GD zHlnuMo%Eu--r96)U)OV8i-ujph-&s#(oa_|9?wfzUJ^7($6+pl^Q%zHykzJh$@N4i z7CZrcr~;1Uu0l^%m`>+)kBeH){E?3Jbqz1WmI5vGlqFXQk&z?jm;WW48}Y?&lCEa) z=W2R}?(iQi>GJL?FVZ8ju&1rOt{7i@IPE9RXdmsG+7CB-)JL3roK(#R z2kWw15grHet2MS#uiV?De&wEsxvmkvxUP}#MsQ4tOAIinG1gA%-Vqnyy(7k$bsl?s za8-?IjWG|9gY(<8pFFN~Z(k6G`z{A88*ZQ849tQ}$A0oy)_Ck2ScsW0U2(a^Kv4aBCrL2O3gaZUjE&+%D3Gd=Q@Y~$g%{Jaj;CD}d2lYjH zM>V^D5 zV$j-uVZSgP;NaN;j9GvJP#~%tfw06gEWKH3{uGb`D3Hy1k+gC+Gf?>aAbdV3JKqWY z`$_XN1bHn4emAlcxIlaW7|Q8WqU%a3O2Hza8&+5XBzFM_~+G@$dTF4g%;(tkso|wVqp*y{i`_JXa zvd7bS(~9;fn(|Azy^+5hxOTCj)3f@C&R?5Jx>v47Y(ML9IrNBjcjr)B%Z~k}E!FL- zKYXeC^VA={o~FrfCkFFQU!aM|285b{zw1B;Y09P5Tr!Wf@t0R?>nC%m!v`Vr(~D_8 zCkv@RU*^Bnge&U#ve>OAe2B;3&o$5iHV!o7c3>e;pD&BKWhM;{zzR0jNft6Y-Ju!v z;@fsw`j8Id;Ai-+Q0d5{CmI)u`G@rH$9Lp$t9RrHn|~n%m=ub|hV(D#zTLmS`w!R6 z>7VIbQJ?92DPAhtvTXvi9c|ZX<*u8lKnz4YvhdeM6qX3G(n^FauhVY!FL?(*05*i{ zXE=lH5?uw(gW%S406F~tK;XKsw&~gEmA;jwT@GI+Yo^8{C%Z2HWJ4!gd+&^YY3=!d zfUcPwm6|?1H8D_8ZEL)-KCe2>WtH#fK$^tVh__%n`5vLied4_&xi{~Q&67Nb9n6}0 zeZv_ldD7EUAFoTazMiU~s!vX)Rh_z9RPR;gH1_z;O3n9AhR<8xA8VK*MC~zjaLMT; zYfd-1dhVSn8osG9kxfr~l1<(a)gRqDG5mSdclaZj**3kKTGqD5t1WL_->J-Z`jw@x zmqNVfUpyuWyvfQb134O%wN{Cz%`Y zP=GZ)&&(On-<6j=IOQoV)pobH>RwbHI!&@stgyY~lVA0sgw(;*oYKD4A0k{+vd2vK z?0Mt;GP323O1*vj2r1j$cR20Z@S=#c+CAuK$+v_DU0p7TEhB69WP4{^^X&h#>5-36 zSBra9Giv3zvF2{m{@sslp0{*o-^36-nMG$ZYo~fOuGM!X;ffx4$oj-*PmR$|{xw*# zX1tOllWdz*Hx>4BX;}^tGo<89%{PD7{%LXbE6+iVsL0kMk%B=N_oQc)wLY^RXs&FE zc(sjL-QXdv>ikmvYLQW4sUN9jBf`@wnx4{-6?X1Z`$&DK>DwX&Ntx-!TK6NJ=BXEp zKBj7tG#!Er`cFG|;#W)l9?hiLOX`{058OPnsI_m!_zpCs@;sxgG00%NaMuXPuj^Ra zP@Cq6{1^Ftal6bmwbn5LA~N()spK2Ssn=dBC+@nLdRgw0Yk5oViN|^VWh$iE*Lvsb zNR8whZ$V}wwYFU+yY01wOmdNQ_uI@p$x&;9mXCLKM2eJy588jQq##1(AY zQ={*?fmGHx@XPqmT>}F?f+QdDU<0MgURxvu`Y-IMSaYj|iK`f1ClL9GDdbZ>mKHuT z#qh4JdZJ;OFfh<+kawobUwWrLMeb?4%Uxvrw#)LvwY!M43L9UHUVj&IM68cM zZ8hsez9nR5_LDO&C)3euqPea;QOX^APC zk2Q{OB`k@Z`F8awFA_b~$l=Zn1|OELtA1EQ4zIj*zdEus$Nu6g+u|~+WbSi=j6MWu z{j`Z1DLk`UezNnge)$GO#_&})FU|2c4dlpt{XNfZZXLX;_eYI-|Lsa^boTYB!N!ws zEhBGjp4#5j>E=VQe{~{q$Z5}pJVsdiUPpqZ;IA2Vl3QAQH1-o@6vG>R)@WFvZ+#f@ z3UWI&>=xuEGvXF>H)Y^utfa?oy{s3(J{o$jdar!+Y8g8<=Je-VO-U}jq&<2;@`GRM zMvkR*{n2T8VPK%%E_!KjWn*PcPqlE@2&4F+z7KKuXF=CCP5Bpn%aJ6p$8O&JzY;xpm(fm=-(~(s&M0y>T}rqvA2&4BrhH=+SxVit{H4nv@>Yr7TGgL?q%Or zOtn#-ZlnCm$LsS{%_o2D#Ws!_)~zqvV%exr^?PtVs^Y`hW`mAUqv-opOs7zFbMMfe zw#HPYHdhzRUy;o>%u|bcCk9I+-(fb-BI$w62`mopZVAJ?ckKHo8Y7C9O;D`*xFC`NM z>f=4$<)1F)5<^INiJkS5B10a zMQ+MERsBWv-D6DdafhsCuZb5$HT_vmr@UJp)*0LxkWVsF>{1zX>1E)>^**+#2B-Rn z%eZM?%VF@2bgFSTt)*WpBz}}hBunhc5j)s?oNRfjPr2$8)v*1Qd4+-f9)fbDV10#I z1~#|cT-MUew{YqSwZd{&w$U$40tOv{`MfopU^l%u=&7u?P=p8dqpZ)){)z zQe~L;-i2ft+ERCI;I`q_XqnFH(O(};bx~c@480 zL)vwpRgqo2!m7Dtgm9BRZ(9#GjUMsRxOF{)1SY_zgL>ze|7smKbRwSIY(&x=AGsKw zVXf}&9kDw*O}tQ5;HHnB(W1O3MO&OFyELQfLYf})_1E7Vxfs|l9!#&mOs+C*728F= zmu74bQ*UvqRV*t1#VNG`GgC(%>kNzE(`*^R`;>~q%qwm_8%-on{}t^!8mt#w+a)%tg<4n05J^5V`%55#27PR66ch75t|*GE&7bQCSeeRjs1N2m3c1xxm> zAFXpw$L#X>LK+Jb&o{8nr`tW^l`QF+<~}1S)%Wddd(dmn|LSXd@Efwf_#7v7452+ipia0TU!oljHX6|;xzNcN!0;EigF*+rHd3mKJ_pyh!`uuMz} zt*pvkZibQ9HillMHkDEUuT4X%I;FOM`|kbhtC?^=`I{^h!3tI+SU&*XXaCn}K=t^$ zG|=ExR-_tI1wDrbQU$!=stB!*`7g2o^@qPngQF%WHBbn6ofl_KloZ)ZP8X`l*L4>h zm4G_o-}J4hs3NC^QbwtQ(*HZop|1aTogU1Ef&l=yo84%=g>&;H$5wYC7oy#3WY{Wfn~k_y=!P(`P;6+g{PzdmW$1C z&5`jRiy9gc|EBBNd@HM=Onzi2{0L&R*M;a_I{<{+sACVFKBWhDh9N9O+D;{5}6-rwQP z(GUI)^Zf%80Y^8PAqeIKu(5@biZb}+2!;Im+r@wECjU3PdvJ8Ae>TC)1T&{cfyr3; zyAMS(SHk~!h(9uaf!`j~R8T6aD2{^t{~^X7nI0F8k>d*c|7ab5VEW~_7g7K}WWb%0 zvy4jM4(a>P?{oI6;<#3RV4hV}0(m({*|v-)pr0>)9(ADEDoz{Y(lXhl`9UCnI1 z{$C^h1JlfRh;x+x|1#r0Fn6fU_LLcha}th1gI!9$_q!;OwG-jr+a!;pOZ>pVk5oZ| zUyl{k6jY?ZcA@NE`@hfd2WE!vFyyHH|4I%yW{&@`g_EKZ_{#&x{LCg!1z>NOw`QT3 zwjtTiIsQSNBTEl&w_5U7MR9F#H9u>Uy(;}sTcSZe9axXJn&x9gF@1EB` zyyH&Jrt^C(E$`*6m5=xB`A{u6KH7#J$|kln;5y%GV?nkw$$wp`T2H!oB(Jv^^#a$--k&li~#XRoXl&FXPvz8TZ3 zB(o*8Nd8_XVUlZKO3(F zu4%R#M+m8pTf3ElEV3FNtgzXy=Xu?!?aFZFQyWiuocCsrm%|$hcAoWb-^g^9%yK_N z$!hS9q!q4DB&1cK#rtuwL=)2PCn@SOURHa#Rc{UyxpWs7>Juchbk z5y{dMsRgIACDKMu`CKl~jt)bpOL#im{{6@ok7r_f4G6>H6iPt9dQ?bvS-fNABiH8S z-z%35SDcvi*)3cDG5Jh%a9j4-;r6T5MJ`90T_=$RCquj%7#U4jt)!ZYY*HZ2$!m(( zZL?o6`{d2t7r4~b1D%6JUzT@wyA3}+z9>L~RMOb>QM~ww0kfj;3`Vc}%bJcO3~qjn zW0zNU(DWT6V6B7GV5=9zi}|mrTa-$5`WUrkt^j+*MxebJ8hU>)rdT6g|@w z-4E7>Ii+iLcc80Ecr8Xyt+^U2RkL#9*EL=w2Bz#%?^7GrB+%R4#M*_x*CmJPZw!}l zNrZ056!OT&VOChUt}1mudLbq66v=ZVKHYi5dN5{y%fj{8ZsT|9&Sf8WWc{(s!d0bp z*m`2$JGm-c%OB<=`DN~oW>#$)We??YO&eXSk4*K``NqM95ADxeN(wz&6I#{{?Y5^6 z)HfVhNn?1lbY2*u52({mXA~Fi()+z#6&#lNS!55V_gDE3)HBoj?^$0H?b3vhf>(Ck z_?0%0a#iz2W}n)l2Iuu=Z5l>LG@jq&vKU!aSMn6#-y3TwOa+a~9!QL>AEpneHoOa^ z9a&!%zB;QJLy&7vn;Dm^HHGFZGmpN zM}hZ$@g8}LIJcn{iUqH18kyN=*G3*t&nWb4j`z3}cQdo^!G1FR5Tnno#r~;L_XCL~ z=B~DsTQb7+xz@CESEU#C<|%cbkTG{PQrq5UMb}6_t|xmOI9-a9tQVde{&wW{i*yQ{3SNtdE|}m zkU~waXHS9!r4*zn7p7ds|Max9w%!-ov)okU+ z?YZ=bd2; zd1X5u1>OW8)H7zFD=3x(N`Nox>PkTJR$NcK&ibOo=zDc%Q zgg{qFdYHND3Amqp$X!n_$!c{ht~MXJ(X^;4FA(u)>0MVr#)d?!xvSuM&3E~pX7L`y?yeho zv&FmUB_bV*D)RydlT`a9ke)#7RooIZ(1%^g3v{dMAOO35F4+PcQzogj-Q)UHt0P!I?#E*3VoEPQG!kGZ`?8HY5*ynQ+fd4i-!;1RLUx z)C(4@j_pX{Ly#Ba2TTG&vo}%PWw|1=H&OE;ITx|@3hgr_=b^gGYKLWSO3z;%Q)wY= z4$J+}WL-RvS6B$==CAf!K+fF^aDdvZwMUUT2MY+zTbBWFUf>jX`xZ4Un{nzZ~~kK$V{4fIK8Kpju# zm>}pq7r&s}^F7zaK^<~=O=GSQtJ=|f1%Wb7AV7F0Flw2sqmlehno z7d&)$uZa1wUuj2g_@Nj7jNfrUJM27fIymS`XXdqr|rZSlV^C0U!wi3PQ}FU1YOtzd88q5^MRz$x31 z2$KZfc&RYSE$OSaK;U!9>+jV}07A1l5zU5zS@vu3Y@~BTfn)nN=I_V$r*-pcC~n|w zUY`DOY*4T7EYIw!wi!bh^Qr2h0IeH#8a8Lr}GTAjySLmu$)wa9j{Ztqfg z(w&#>c}G{&`~)gCM0Zj16TG(U)om194OiCA2wHg@f6C4cw9q+v(=`TGxEjBO^rE>> z@LU#a4Dh&`0FyNW_zI{!1j9`P_y9QlNp~657E(esoEX4W@~mkH>@fy$bsH5hGF>BJ zH5Y1D52*5f>k8HnT7z(SfLDN_HN$GgF|aW^f%@u0_UaNU%o^4MejvsLVgQZ47o%kD zJy;1mazb(B>7T?1RRt8sUs?PjEn?*&eB??Uyg{HeHKAm8g17pLSV*oczN8op>meOC zm8BOluf=i^Yq5M7@Jart;FtALA)ubJPTO96MGTSM6oLfi=?Nt><|!;QtrnJPY`j;D z`v{Gh&D}-Uv4IAb&&#VFTIv1c#NWZd5@@@)yAXW->lT7G@aZRR=Jf*kc+G6+%)zihc|S-Fqa?~i*pk8ZaT?3YsnU3&}(a0 zIv&s*2my+SIZKE^htZzoTq-2Uov-NRX=Ztt(~ciBe+HVfE#)Gwc0b7pU=uin4l4%D z=L*>beff!sY-TcQL@kh7Vr> zwTEE1i2xq}rz1H$^WZ(YIq_tqdB z9^e&VXw9&iaSUwC!ll3ZkX7QP!mMFE;0Iz{AO_IrdohAB0#*W#oKPHjV#lbwD1a8h zeZHIZ(Z*MD?WKUvAdnX?Acu6|BMluL*ymImKdD^ShpYMP5%ElRY^mA#2e{M0J`Iz1 z3-jAVid~tngznnBLvm+$r)iCUaXAa z>;OsLP<|ME4tadIUm5VoGfy}Z3Xq%4L<&OWa0)^Pv3(o!_hWNAln2KRyv@tgKaLFq z%LTIHKbvwGY9@Ey^yOEIbJwnlV^|)(l@?#eGuBcqT_l~$i8 z3kzd)`!rwcAhhvzU=!G@T+LLz*!#MC7<1m@1YJG^EZ2%$BTa?nTtxE#8c^><@Zf8~ z-mv9oT z;E*9q5_sdK0d^Skfa2GiAn>{55s1%sfY54AM6;n#?1Xt{Bc1CMjtzpF7xVXH3$|;3 z;)c9^+vW#ib3f#{YU0Wi_YsE`tFt@u`ht}x{lVv(@=61lrJsgE7|eTWj4uMEE^U2l z7WWrP3U*ZoGV{Z#*2|n4p?xVB_h?u>objSczHo2Oi%R)TonDq0jIYK>QcCq&i-sYu zs7cq;c;9Jx@;;ht3}Qqu*R84n1&X_Kho+KG;rDu^_JH(np5p{zJ^84{lbk2CEQjcj+A(#FUK- z-wckpDBp!|A8^K2R{QogL{~|d4xfII@mcmfvAz_p_&^@ zYLtK5OA)Z+OOY0cvp?`lxBUSfD*-zpjLwFA4L2^*HoTU~y@2#JcfYQOwg&6}-PcNeUve=I1w3P-FgibE#6ViACpUDfhqXK`07g2m{ zf{-zwt_?-PqV89JT$wL5>8udOv`)y}v`#8F_0e7m=J+q&xsNW=avv?JXkPRmWaFsl38UlNaLD+7g0!F4);I?ND z)T|y*<^9$btZ%ml;qU;j07Gkr)r@0cW2UzGs}EUQUMkEQ)&qVZ#sy*kjlLHnxb1UKY0=3ynep=@ZJ_Ib+iqzRe1@ev?e3+H| z#S6%}hyVwucLomLahZb!gor?10L}wY%@;zgkmhb=fkTE)5J|{e3}6RH`gh!b!RL@S zU-?lHcr2bLghGTu>2^H8I~(a-r*Ld+!@)blW*@*WQ>QPhS(J}dUY;JEGUF*s@>P89 z=o|hqDbL4S{f>R%gtOYivZYMdhE<~sLn|MM!bSD;i4p#rN5$492uY^G}O`q5k2Lk`)28axK1; z6}+@ien1+wX>eWrn|toY zB64AE;>g5<>BHB>*40ke~ydUX7%WlvcM^hQ-49QboV$CNO zNo2kgb8e-Vd75$Oy9`E9A?%A!KRJEB>=gyU-9!z^Qz?Y&fNHdwEH;vM>s&n^S zNH3h*vzyBzN)KP>9$*r+6rTjOhhVsf03QIS_vDvR8z3cQ!-)Z0CC{23hdsumRBfgL zMqvz|^c*?u3TI*S)aA6!Ts}mDES5zyI{Sr*}#1+B1;eHv|3>Os#xVy%V+@3iUq~p zyZ}st*AA{0uZLw+z3jAZNg;Y^NzQoTj+NE@!KC+j_l%cxGOrozdXb{6@m@E-d6ev} z-?-L5>1n=Co_PK00n3_x58tTsdWFh$@5e^2oNv40*ss}FvOSD;#gRW{`&!zX4iWPs za*;0!(h}<8^cVvgYV><4*DbJ#_(n7;SY2Ph;FkZQ1gz)VPyc7I1q2vmAfb zksotJ&VO}>W`YK+1U8%)z?Bt@2%DzB9=VBt%IXdg;E`)C6o($TO8>?cOD|aq!ZCv} zc$#NeeRZ6=J*@bO<5wRb>KMcjEN?}tj&;EU;#b5*OYnM{}gloX575j9xf`~cy<~UiaeU!yu)-Ar&4Ne`{ zr_0s}W4JfRuKo%DDYvAaGtSS+PBXf+5t1}gdJ_6egiND zu#)Fs0WyH;O&VzBz4#g*`xKA?OgR9!0fT3=3|OroPH<3ZuyTHUY-+49zdD(R{Jk*Y z*#1L;=7-sk8FwkwUY9?`URM~?aAnh2uF374FyB|DV~hYxqT_Y-MQJC zag5fnfK(uO$`-`3t%NZn^-HOA3rV=ysgZh_bj~LA1w)X99))fZO@naKSQtj#uOu8= z#U=mB0)MBuGv0C@{0;C*5BQn21l8sN{)}Vn+v3owac%yecOo&K2Gd-5Yh-IH+gx?R z8i&l9SnStl8(?kdXp;n8i{Ag|c zbm3fHF+YQJVRKmShkmvn56iimdBtLZ+U&dlZCfKB0+wq{^r zfCJP!pAFw}nS%v{h-XUxI1fNIUkFt{ox70*4jGCGO^vm8S^}p_s~OE#W=I5;#j4-s#n`&Qek1+v1hL0OxdW51D?M* z{?uqY9zmKu%N!WL-y@r08lJ*PDopGD<8#`&r-i@ABm{d8kDn^QX7*{8>LlsnPaw1_ z&T=;=uZhKF@?lJt7u#g=Az-;yWZfnzEaxJcT%`f^&ZNco4D*0cSRPY(R@fZKpO^>8 zB`vmEK<6v_z%&upY~ox-s}aPwmRer&;Z*-+e&w{P40qu8KK`hnD@ zC)Zmyi+(a46g=>}{psD2{#+&V;fQ{N=kN0@A5y*fN%!epVSV*p*C)q@FRF<2=4E@| zu@W`s2ODczEov4aXv;p^MgjdUi#L*XFr7bzSBw@qM{j!Gz-nuw-$HuPToD47#d!n# z*2Vyn^8$E%s67P3O$7J=I9;T-j4A^uAsbE%;3|36Gz9h-gLt-$3K*H57qFTOHLC|y zdB1f9>xZpDI6S~Bz|fjuHRBlAnDL{(`jCCLgbK5U^?)CUae){>qwmECCU{s0JaR&D zjUcZua!}&E2OBMIHBB599JVa0zIVj%YyYQwCydI z#1Ji)#Db&0viu?%TK*SWMA%+@Wd#?tlGW5)MRO6A`hg;O_&CWe=3fLfX_)z5OT0nVY>D zvU}UT_LL>~6xvrAc(zUrNRAK57(89SXL@(_9=kZhal^#BgBgrr3i+p3dCtBM6!;Mr zz^ed z+WJ`VXY^Y%ASZk)7o{aA@MD(UDn5EA*v^y_3u<%pjvoL|hrNA^3cUFNr))zsOcHnl zuMR*Y!QbIw@VVsgD@fJ?k2~i?G#iTC1@QjCOr&!|fn)nN=I_TgpvZ*d2Hxi7=^w`i zf)xc>;hjx63ku3zu$|!esTzc*@A^ZsFRRZT^6JB_vq+cE`r!9T)IWHdAc~2&j%q_R( z9MK#qVFVA1Q;sDuHVBZkD1&ac2d{NgPu9e&-KW=-O~Ocu3&h6XxccZx^!m4$-0L*| zWQ$}~Pv*LNhKje>HC9~~N$l?`wB04M@|Kdw;=z2|H0lWbQun%?p~=@weAjcgZS`k* zv#!_FSXl`DJo{d1!gJ&7m^JIXNy!J=DrMsXWv4a|-eEfTZOd|sdmD{Rx7j6Qw7$kv z-~qo)=VOV7VzGH^6rJ&ziQ5CllZi{ezL0uoQC0F)nqpzFa+B$s2MJqS>{lJ`HSWw5 zsWDkYbvl1d*)CCC+o;JZ+gp2=?S_nJr8o1H)Hn1BZPv(gz4-B<3m@I~7tHWIX4H1X z81`+G^d9FEZ(X{TI^UgD|FBA%++^8K&{R@yw!b@WLM4~Jy4HzkR*4JiIH<^{q31~t zBucE0Vmh~N1G><}oh_G!4eI~2uUN^qQFnM%7uBD6S31)EuKAHg8^J$xmAL&9`1dz@ z)K2SB&<)*^w5s*Pgw&cPHR$z@LWL_BS0bzkL1wqmhxb#^jX2$LZ?m|9&c%oDT`LT( zyD|b?3@z_FuQU>lYKSvn_?f>GlBs{Np#gZYwAz(ey`*LTg-bz8#B_8_+ypV` zMsMr|*XaGqkH{u&dI$%BQoaI#>=ectGdDfKJOblsfyQ>VrAF1xHLrbx_e@Lpe*RG5 zetnU%*Og|cS3_^(E=@CkDLpDo7)Ogmg;x-W!mRZX^_>B{m(>4N6KQ-5mnbCEeX2NK2!Xbi?pM)+3@5m4n@bi_=yk5$wdsQig#Y;}iN;e--2Qi^J^z zP<7^xi0tI8vpuxs`}>(vxW|-dm}Fi^ftJfW%}D-7C9Xc99Shgi@+P|OSX@)<=awK^W z@bq4a5f>pEGrzwSy7w0wp59cTzHC$BZJ|jV=V_;|E^@OmlfLpTyTemW$tMoyPU`b5 zZtA_>%Q*{;gX%6W;!f-{BZ|vMO?A%f>JW!I74QV}=QJY&e@)%D&*~P6$LCkmC-|+V zw>krYU^=!~BvdZ&)fSsH39ch-IM_MYmjyFca}j(w@+zY-dB08SuK#GjWHGxmeScVk z*Pq#{*n8mhg8QCB|A=XjvQcklvptz_iBtIgmm>j((5+K@%#y8BigFW2fb>R=n74l5}qj(cEi>A?4`?I}p+$NUvi?A7Op94qd-v;cQO$P?(a0_NYtb$8C#Gssb8y zsxzQ`x9lcLnjvLh@uJes$;svUodS-Cam~<2PlKA~?b3G&ly;P7wKXN??eM{EO{)bQ zk-ayd0YF%Ky3J`B*|UJ`3SQJ8y4gN=-KmV@Pt%FslE|T-i8~-Gy?JD4(ey(*J4s?2 zpGlmNbYgqUH&&B;wxkJIj^3WL>x_)lmAI27)~R}TkK4>`?Qm4p+I%>aSW+<_$da^1 zGibd+gi zzP5Y)S#r)AEB=`l{$yoDt@B!5ssB7z2yMlv{emiIAO3Mtn?1Sk=L)9;k(9OU4X255 zvvKZU&^P#;Jk9~t#6 z%v&n18LVtzkN1Aae1cZIseb}ZjI=yqG_fT-fzDK|Cat7??yG$pZxz%wnoxl?k=K!_ z`aq}8Pu+02dF9~vsIUY0>V34)=z>FUsZnpbrJicy&Ijfb3rw!Izz)$(yJ{j&nF;#k zc}qt^36pa2X|PLmXQ{+KM^M3hW-h65)q>qqMsvDSwIW5$P{!==4z&;ia}&=QEoK@& zBWBd>w@%88);v6pS=w29a_hJgrHd1O@l|P?DPr`aX8SheW+FKioq2_tZF6G}T2@Pk z%CROa19z-P?}@BN&DE6Ugmz*pDV*t=OewCGYH1q8AKB%}KXA!+p~aeTF(XhEI5=J_ zQwu}^nU2`PRx2#OPq5!tFQlA!?;Ou)v9D3Mzxw`VOU`2EOi*ZIjfG>*g(Mr!ykDw| zV0o_F!?5He?5LV=O-Hafm|$L8HM07len+-j4euR&0)b58xP^0JT99!c7mo#P*sh$( zmV-qs#=h1kx?U}V3YGC7W%^_HJ(`h}=)CNaSuq@OhVp5u}@32O8?;xP2 zcp_kL^1vpHVI9X5$=({#$fttjS> zYOX9pN|rh{s^R8D3(jP-j%0<7M{*a8veOWCr%nV3ZDg6Y6S_@2TKk|n#GMb>hnU^e zs6La4@((D4VQT%gU7hZaYn&f1yPoa1I(AC**V)&I#>!Vr*rqvi=HYc1ggbL>EU!+N zfYEm1qivm=CUmusb zpTMWfOiJK!nU@GWF0=oD$7PBg@c7y+G5AtmIbz7SRv_P6fqZKP$T$A_+qYIA-&z4U zEWdvFtrf_(Rv_P6VgJ?&K(l!HC+y!^0k}86e)`r5`?pruzqJCeL4N)1TPpy^%jGAI zZ><0c-(Np{YlY)mD?ozk*Dt@d!tt#Yj&H31Oe|l2`_>9G)3;`rnZC6HkRg8k8Aw+D z?fI=KW~Og#F$4L`m;XC6kns5J`K>u-rr+B8&QJSWd;eglW&W+be{j_PgQWH!EVTfG z&)4>te{1hIqFUzPm};57vgutC-u@=vZ)CO1zp>Raf1|7YJLp`$PMx33`u?2<00OWd zeM>gKnhgp8_=>(UCH)aA2f*_SwWQb7(J`kq^EX-gIV6Oh15?zAw(-Hx6UQ8@tV7XnD=y#rgzh;asr`u0T#KFSA4q;^hX4dbo z{sA;r4hGggO-BckjE$k1ItHeC^x9@7CQwr=%d1#jE}x&210Y^yU;bzmIhh| z#s*gQ^xB%H^jc7Q3xLbo!a&;!s&i%CeBEh(QZg1+5Ca&X7z6fk$p1pL%bo4N6YUCe zf9;-`cK5X0_Wd1n!ljUuVDUNo*ys= zICcM={pQ~&(&yG%0N__w<1eUp7G@5BI*y4AuoA$3vshp4pPyBre=OD&O#iac`f88; zq*zxl{QmwQFa!Zae1Cd0xulvhwKTA_0uGDxmYTXyZB0undTUEfy{o$Pt6}()@~~Vo zZm~0i0Xr4^_X+e1%Kc9Sx`NwZF+#tf>#rd8{mnlh#>Vs;3;rKjW(KBKPzzm6Z798_ zsSdq?$#Y}q4I&vk(PQ|BwBnl_pS#$R_)OJH?EzngOOz(Ge} z(^L=mGc$`zq=BFHt^)lFik}t222cYsU%FPn|4(K9g>B(aWWF*3{x{?N)!X%x3+l?$ z_%7TJQ-c{O`0*vqSEPgaszIx$)Qaqrr4+97S z0t22f@c&G{UoZ^*M7}GK{|)2!3tP(-c)tsB6V30Qyu6xV-r|_z&`=Y$Mmbq?Q%P|0Nihy-+T&JH1k(? z_fMk83J~ZsL4b2F2&e(`kJ5YNi8_?7?U%lp5`T+Zpo<6;mKJ+); zZD#T9mw%MRxiUAt-Fp1wW`Plu!wsi&A?_&Hgbl+>{{E?2ZfSOwy zSU|rb_|+)0q_;J&(x*4EHnuVV>@?sg4{Q~eR{%eP`wLqc3mCWn0^G~Moh9ghDB&+y zLw_RS6@dSiG5m#H>k7!`yANEBJhW=MVS*r6rjD^tkqq>wxDLX26aO zK=jo$eRaqE8VB%`vRoEi0t3vz5Mt2ZBg-#X8-Faz6@>oVarp%`eg&iNZ@r2UP{Z)w zR3)(<5U4kD5j2*$YVPsbKNL>mCLTYvs;5~w=LzyX|V zFKZorpE!Ss5Wk{~|5%7C2>pj6@hc@jub}b$Z9fdezpZ5U8ybMc3M?uMsFk&a>GwOi zA2zA4AxuB10x#osnAuo>`g}l9v46~kzeA>9IDr3&Ojoe_i^k~})H86_2D~r8ND%|R zgg*$lVq*jSn}93eXsB&$ZTZh=)AKM52wP!kyhR0jlt?EXp#enI;Jg$Wse3f`Bc z->wY7@9|Xs*$`aOvj2v^p9Khvxk}&PqC93w(1z}um>;DFLwHbo4UWiz?v*Arvt$FG z8&_~-isuXD+sh<%iI&;f%e^wH3}O-kEq7OUtrSNGOC>{HY!02~w=^VN401<9mYUXg zH#_J-T|?o)v-55A1B)ZqDVsyGX^E8|O_v{yYGjx(p3W_4oU_(&C!T&t&!i|_Qb`oJ zj;m~9!c!Mtdp19FzB^RK+c(V!+MaQ8;XXTiu&l+iGwt4vedw?($8pl;bbhvbV!5_y zX+Y77M>-tFT|TpM&q>1#tpYLzJ{~j*HkolfoL#TlaV!h?(4$!%n0T0x!Rt4%b{@5l zMx{og=|**qkX}f(D@ByWSgYujuaVD7{$+q~S7Z-OarmGcqD**a;imTEWiI27ZI473 zLTC9PTH#-&*Hx}_lwqqedb@XFsNk1P)O4Z@48e0Op1#4;_rUC4lcKAV}( z==oI3@svtE3JFL!8csa2u*G+6UiRdRR#oEPY-n2+p@8ks#fs`8;cxOxz&?tIjHMA_ z+((!leiKe+ncmi}HetYZt#sZ%`c@Z3Q<@^Da4{*z57+Fgt~`xv1E7d>mybKKF9jZ{%K+b!%w8V2VfSevaQ8l9(EjAtG< zZ3~%QFMOBGZZmSlJLSD4Es>WzZ^?#DH#z@=Sp-^Y8D-Vo#tq?$=g)&IT9-VV7R;D+ zi{Gj4+m}nr6KQolRLy)yJ0(S1R5ac@pxpmF@+4vKS?!Ofoo3u@hTIc)MKn(57=bJp`;>vK9so$;jH?dRjg+@(o4+O02^I4IHs@t&>) z_tsLQah>4s0-Rer5_ttyap~Rn?1);cup)vQ1CWO^)1H%`HKjNyI z-6tP_RTnkMdYG)6Du9Y4iQYNrzhN!5qbVmd-dM}d_!4GbugFK7Faw7*wXy$vl&>_^` z>_rNhJ=FmV)I3$#DV!_O{4l*$*VZ8{0V9Z zgD*$4NdV$lc>=T}r)P4(5D{|~f z^JEb-Ch4xUbl*$kYIGmd4(YJs8}Z8OvNTi80q#q9um{+~E9MOChE9t*(wgX?;3Hu! z2q8WNwblZ@P=d%IoQfic$PG{eIli4B+~bCU0E5@uF(FTbSRt*+_e;|^l(1wi(aD8; z@Kf-J)6zc}D=be^gqr?j&xN(is3_HN&)6^VLRPd#iKaOc za&uqpf{&(=9^UF6zOPvf?V!IGBCag)iqtO*?jnpk`13%~gOHc11UO~Ya|e87RLEJCHDvHFT62VX>}G_a&` zN`!!KqBLV?WWi?`JvH|lRS0Ja5_w&SJic|>Vm68Y7I|^>t#H*b;QPiS=gVnQ+u+ym z8Fz5WH=&ccocgxj?&BbGOYg(_~_SGERoXs=`ieiFhXw3f_IEwVB3Xr>pA<-Y5q!mj3z#?VB; z&Dv=7n3Lb!CxjMBXfC7{4AybL^kUeOt`e4z6J4_Rgr~9L2}$=aqe~Yp3VW;HwB6XP zI!6%r823@7pv90p>v$g35T>%tbzbTj5h|k+^#>gIAyEa2cw)Yi;@mu0A+_X2FqmRX z13Dpx1olWWrwl$48T(HT0@Q|O3Qa7qDMvx}9pYW;!D#`zP)RyhzGKciIPYXn@>%x|CO{57dg@j35jviPNRGK77Uu366VAluuz8RK2@__aRNRS@xs;{?oU$pjq4# zL^B2byQcS-1K`zh;5<{q9t_=ZdpMM+1bI9zq4fCtuj!CP8es8w1=9(DPx9~21 zel_MNhN4Cr-p+Km-tlgf8%QNLJv@z54_4l6>!xSZ1q{9puP9#dpS zm%rGY)xyg3MxM=hl&1~nI?sG<`RC;tN7i-z-f0SPzvhB#BQ`wLQeFOR)Z+*oo%E)j z867K4&nQ-O+n(O_&Gn437xE=acK=9(H+-MXVJEsEa8iCqTk?JdpVRnEd)b}OXLaXJ zR*|1S@tC~B2@(>&t|7`cz+wcC5ROq?cdew@RGUjIR2a?6wp*rhr-rKuIn#c>JPyQD zJ(T6dx>Ma;WBK}^9%Y6MVq>dRvp};6vxIQOE>fM;dZspggMTB_)h7DjG*+#))w@3} zBKeGg*`a3q>{HW8UF`)Dzb^Hu;;7@fd0X7N`uO>zpy>qTIyOah+fohd(#=eEo2t}6 z8^$Rs1_K_nX795Zq-WKHmAQ5O%kzL0=g_u$j%0og=Xh~fY|_Vt}zs<^MCoH z-}4@rS*}>O|K?E23IT(!9!h)gCIWRzw`%INz9bf;B8HcM7qpKu(B+dg zBX1XQ;k7PS+t?V2j8o)2 z3V(Usy%8B-dTWHdJQD9aLm_b*p_Y^j6iby3$K|K{B_}QiM5Ic^e#s1(0W&Vs&WFzw zi%(By^n!&qEcT4Rl#$g>S10e8NKt47L8{C?ZjP#TQ;m`r_+-jjhFP)n~@8nyU78d-;od*vmLJN%V=x z`qAv?`)xsW$6Hk`UZB~!N%s9m`C49^1&}0;Lk42lk|r{z8#FxItR7n&4Q9fwQH{;r z&pluo#2?UBV=I42Y&jRv9xP>sd5*@yz=DcJvJyXEa*qpnREckoeR%ivf+mT~*=u=SgUwCOmmKZ;QJ);u!$MEjcc#3F%B#~bKQ^${S4_Rm zK|Y0flW~pGB=Tat)>(lq@lJR#GTr!&pBRbArx z`v%`!n2}870N!iUFGGbl-CA#4FQU>Wsc8tsc!ZswH&(J^Xc-z1nnEna%$=n)}O<*}n_UBFPPU%i8xBi|T^ zd;je=V!)^=^K8|wLu+!@&T(xA>n@x2%4YD3Qe+6HNC@&9);Evegn@DzHAm=ZwDkyQ zSW3breb1;Q^uhy(yvXk4Ay+6HwsCcZOJEDG=Pyb%e4?^gU+0d=RngibJDY$h z$=tQm)(%H}T2djko$v)n$@_M35CNdshw!{2;;}} z9`9sPHv%SQcgA~YAXjGMpo1|(C#pbkvqrbJOnGCRLXr7o_Hy_AdXWS;TMEP06=l!- zBfJl1F_MKu zm3nzy@SN$EW^T`|mZu8cyw=H8x_uj`kGI4V0pe2pH*ZyJU-f2hpUBCuyISEAOOC8u zze!rsRd;&k&B%LpN2@m`vsmISD5Z&2vM`+8@OD|e$&-wm(zpGL%4CagNp$Rz)U>h; ziwZlu#IeI<&kQh8qlq8oIKNgHL#Q{mjvVsNOjY7qqaIuGJkN-4Ex~-ijBZ-Qd)u1$ zP+zQ$0HIW&lJ0BHnSKm+>A|JrffU@)1-Y+Zo5;!-1_;zl%^XaGI=*toe(w~3TTbGv z0%r>;W}*zFNPD;#7-_6R3}0ujoM&{MVB+<}#g>QoJKm};LFG>U(gI0AWYEF%K95te z)^v`N9pgAvc2G0^fv^E)4McP$xNsP(SIusW^q6d6+p&Aj^yN4$5?QiJBZ~dSP*#VG ziU;bEuDs~&!YLtnyFy~?<_?=(%kI9He^b>_~hV)6Sh7#KRX79fr}H15h#$&V`h8jzo4RJ@~W z16zn>g=rEw7Cz=Yk5lu-#!*9EdLvlbS}(S~@7AHsNs}m@ElrJRpvRAH8~fBou`?Ot zy{1cu?~C50GTIK+&iM3>2fd$LJZPcKQ?o~c$Jn`0^ZnkUc?P&0_MW6oyy)#C@lVh1 z%yfnmqvfchwNllHQ|o14HEp=wGc8T*YURzB>5I9QG)Y_D+D;{9 zPyIFxg5dXV&A7hU#4_b<;(0U?fxHnMf`U{F(;SHbGb0+e{Cp#T%86jR#Bt}P=v!~t zD0c157UdaEfyr!C_+4zWYMY@J36LB^cbT+>Hx~Ch%FRWK-0O$a^q|r;yK%D!#*aIj zYENs^4(K;)i7uuD_SSo2-!;DxZtZFTpaHuR(PRfAo+hM?_Uf58{~ z9J3V9;JO80=P)mJuK5~x`7l0CG0jk!aiC`@yG7* z_t?mJ2~=eYhcj+aM}55za`*9rc1>?ol*Wl(cxznrV<x5 zgBv+-sJ&j$MIoZp`;j2Yg;25}ZoPof$g-sbgK%GdLFLd7Tz^5SKsQ??DA4G`Cjh@8 zBl_gSUakpBfYzIjzVk2IJN3kis0JqBnqL%Sv*DYP`q^1NA@-y6-^^njlXXW_zJtSM z2lwiF#%hzeC8lYkT|tG{Ee=`bFz!L(us9rq1g=}jHy+-OaC)sSM*g1jVLUM{&ZylO zDF;a4Ah!`+wquiM;u{V=aX__*~e7Y02YfHFtq>6s51{7>udisBRVf2Lx6(cy6| z6UG9r`gp;-07f%pYmN9&j%$|Iq#+bdYbla)LAgW+E*PmB+QDhzhj87O;KeI6`J@ri zn5SY6#v7kFeKEKS5hN(-C0fg|_m!5K(qMMOJRq=@!Z)|Q9;0^P31^6+-hW6;EL0`E z9_&L%Sml8$igPUqTOS;n+zd18hxI8ckYrY7$NO{%f8@gyrO0UV+8B-O)F4*5=Br7# zTRJvq8RVv+Mh4e(9IY&@@Jzww=%V-(0yUmjjyjv994e$O>%kegz-%8(|uBn8F(sjNki671ny$lc95)NXWce2fB1vnXXR9$C`0WM9 zL$2YZa5dhbswJhE*%tMQR>S%7(m@-4LHB;s?M3u8jfrMo3f0)p!WM01bV4Ww&0siv zX2bSWpF;N$*iD9la}4_X`4YJq9I&QLOcAn!i#96JaD#&%gUg8T3Rl*$7wGBRDR9uE z6k(hU5+@ci20Sdnk&;%&nY=k(%LFR#R<5|60)1V!5=x?swIcJXDA@}zmh zJ)mSnDC5v=!GTO4$qy^^!-Ayb$$UFI9y6gs(TnVH3HJRVDc z3n?IY?3TvckL@k0@=P!9ym&?&F~G_us6eKqLlXu^eSPAYi03Y{m^qwGOj2j*y=M1G zUl7v}S2k!>OMfw@B~eqXhSG%k!%ag_OuB|h{0r4$1P>uRHmRKPxAQAKP&}pul_^R| z?ODnmg$hu?s#q56p4EhXYlYgLv!fYuRlQ#BLb{Jr)V1#QL-M=QtdG;4Q|JVnDJulC zi8{`RqFY757eB1UTqaYWa${_(8$WWGD7*gQMcA67iR~mvxOBi5|4P zKtP-eYFeE*-T7ozck-D?!x=@|(h4*(b!b_!zk_t2cdjK;VqK)^Y<#Who&Tra(>J(Z z>=_l0&W^eg&MJ-#gvvcGZrqjnF#SiS`@dYP{`aQ)r9u6#raPZ0kUwZitisIt8#x5) zZ)6Uvm$!ug2?Oip4c+DQGI-(gd3jwW_jiyld=ud(@8W*H3f!)36Um4&9Zl_jH<1r*AttI5pFq6G!Bvw(G=T2OXC z3>Fqvc6N3xRvi`~w*ssQhU!4sb%Dr>D}Iiz!~Gxh8OS*Uav&i0ds(v0Opk|i8O3%tPC6+fO`qZU}Rza!(8;g4`^*o09Y1gR$Ugr&85lA zrp*Fo21B%TSlJ<(+N>ZJ79CA6L>J2OPeA{|P50GKvqBhv_go_VL#M&Nefz&c`akUS zuSGnufSH(qwF}~4V*q^(6enf{16S@~79chZh_wZB$p0XG{OloalT*{C^M5T z6ru}Z20=BoAW$|iGl&fe(gAMU0Rk5Y`#%Bw3-|dzG|KlrUvkKNThUkg%nnde{7+Z( zf7s`r3?X1=W4r3DT~t;vBM?J(Nz`EOdmXiVMw&}XfBmI`_)X&oPa!V$wteAtzRvCX znatYC?oS*LqBc~t+eUN84wX4Mt30gx#i@xJ_Q&}YbtNN4Vmli{yY?0mJx;b1b{||E zl;wh>Et5Y zy_>vJ`E?hcCTw}nm`+MCPjhxoPCl8zS;-xMnb;whdDJe9Ndd^Hk!fRfFfIuM1uNy9M>4Hy)jE)l=C6fDr!t>p#PkZHU z)btUs2hNGSQXQTxdylp5wGjo|X#3anTqM+9kV2-JYQckzg%x+$ARgD%cgs23I z9-k#%9PdNSsA~^{nPYAuJP0i;%FM}byH9Y7fwU!yz~QO*CXemf!)}KF%!+WvWxBW` z(`)53@lY&P6=meCTiRZSG<*zNBVFD%mfTC|YFe4JyI`EMcVguXS91cTjUDU=5YY3n z+?EXGwA^E3KwqMJ@9lcbzh0uk^mnbV-tkT`ZBzqGJfXCu{AjOR!7wYP%V!u!ZclZu zS@6Wl#ruGk9H&kQl{J;i;F=K9WJc-Gvc^{Ln6N3I2+*pzEEU0=>IkuZ2h zjc183BqT4j)*Q_c#|0-2m-;zK+Gd5lQ2z+=bNrLm5t&J!O8Rs)$Ly!n@hFt<#DkYj zV}|C0pYUwxE1cRI@*<_)sLJSy4wP%1W6V0ExrOvV?9SRVvG}#-jtU1=DxFL}k?oh_ zy{U^`)ez@HUc=mw)JA1Tvqfdl8RNbJ9(`Jiiscg+WwC*vdB%QKlwPr#C%Ha%4xr0i zLyCn0Rw&w*h?YDq>g@B~kdtlW-mYG|;^pYDOb(iPrx=Y|kRBG{{Epw24%$PV8MHvI zn{iWU8x}8~)|1FD#PUIusT0PGGB|AzG*U+;&kCgMgylo0$S5ve9c82m1Z{EcJb#*k z7R@{UL0zNKl9OsS$YkG6KxLRR#x3ZPi?wIZQPSHwtIeoYK748>T zfgKF5+eIa=@dk*{%>w2g*0=(Xf;7MQVOe$qq7G24Xt#yy?frGtyhn!1Um9sNjCJee z9w@#EqKk|fZ7UrRB;%|46r9Hk+6!3^`JC@}5T7ug7&Fcdt}!;dOW=?yJ^Ukvx)xk+0KiPz6D5>8W|XID>aS_hc#E!ltyvpnw?{ZGAnh zdxwVK&x0FF5MTKd!da*{LE%3!n;7-W!jnTzmQ?BA3G64k#G5p5h zi%?RO7n13zCNRDT?o8KFz4+DCnzcl{sTssy$PgyH$;4>-xPzlr&=APK-gY-#+>{iibwp0Onrv zd!P>zdIU|JxLLsLknMP=4zImLkcV=fj4%Y;jukR^pGgcx$|&CU@rzE= z6O8h=5NW4Gw}6tok{TRsg_AsJtS6rq8+{|@8)C0c0(+N}s8>$hDB@1DlCL7$5ErX_ zsGSJIlQrpOQPVllh>cJJrA#r#*8FyjceU{6QtjoB&4P{~3Atx-pU1bl-TMda-PGz;p^OL2R!q`@_R!GHLq>9yz%2xOP(XMJ~U~IA580h9!eS?>^^C% zz-b`op!XJs+ZdT*0C#LL<*Y0^@?uaAh8>!Y!J|JRZj(e3NXo>}cf}vs7VT|Iq;|DCh_rQ0O5!+WcUmmpYII^uuWXCQZt zfrFKe0|@yB@;4YjU%Lk+2VBzNaR8kK(xxB`z&pV#EdMK4z<<_hwoCuwZ;q~i7tjOv zdajy?Q>qd{W@}> zYK>N&5v;kM85|tJP?lbN;;mwwSx=G-UenR`h}ysXOq}!cJJ$o3gQLxh!@YwU=ZbO{ zaj)}+&|`CK_v!upz)#16aM28!?tL8k+KLVtC8TVJ$iqto1Zb$;G^wj!m+sJn2F zs(7U1AE9Aw1TX3kO&?k(J%rP1m~QV*8tZj}>N)duDAZq4)P;o3%=a}&K*2?w=S zdquDD1m&*YjxQt(;li%@Fl<%t1M20d9k+_XgT6 zb2}!RMFP0ME!s^c_Q6hC|CUlkk*CggC%IGST63NtAjEGxdzD=&&^R<7ky28pMzB@e zF;{u(h&}mY%I#_1!5*zFl?c@D-0cpCFzjXw-t8_Nfo;g2*+miBitnxAnDzQ5s6?xA$&|GT; znVqpjuszHR-}ZDOg^AoZz~*Qn^CcZCE!+*vFyfE1 z-X>P!7cThcr^Mg!ZG%Hw^US93k4fsTeyhtTG3?ppv3;l3gwbK@-l4-b<-6Ms!775C zA=Zz}wcc|~-(t6ZpSKQ1Z8ODqR(b8|;C2$qlo@_6o{|BQe%sn`t|PT&pwb&?AIiGX z1HKmI-jj1Gb7E{SA!CO3kb5}Nu z`ABW}(GI4*A6^vPWQ#}a?J})|xxDu%ovPaXgq6+)n+bGHl|J0fVoHt>`3LQgrrDuj-_L>_yi;ec%|3B2EuwO@m5n|u(6lV?4N);zZ$v%p6UnFY zDW@Q{{yoQ{%nc`ye}_>MA{ON>8vf6@^(5DGrE93X^1sAK2Zgy9+L>Zs(=d6u(;v?l zXIgL`K5^{V*j*OTk0Y-FZNe(C-=u`adTht7U-g2@WD@gv4xCGzD@KZ3BvH$(%S6D4 zl+d!Z2w42|Mzij&tq+5ni@-4%-rxgc0sO8`l!?|?Ql1D&fiGrEg;7s- zdfr>N7?-2m=_(SE-k}3a9IJTxnPkS)ytO9Ni{#Q$TZMTh4lW^RdD72{SY2Qg-!P^S zqxy~}nqZF~Vk+4qQ5D+2e0*;&BIYpt%m^fiPkgA=SDEZ2i1pUlEil#_k8$IfNc|uo z5_SF@Qv;{^;D&H-&BwT=2saa4(l$iYQ_Q&g*!MCfJldki7=0Vr>@lXCk%(u{!W&g? zw0COVoFqTxRzHLd2{ex|9ZFR5x#s^EHV z+IO(7{$eG|LL%=J98eC-UPhX3=Fv`I9gFkr&q7|{ou>}zSofPU^G;hX$t%>BLe);2 zb)dA4vRI})b#kP&Ve~0O@+=>$AE-oG43l>1Hd|Pf!Km>EQ+EyA=N&34NmYHJMvjDr zLHbg{6mz+>m#vG?r!8PF-f$25!;!j?jjs*NHo@k(%Qlx?a{wqsebUh6DcfO3S`wdP zUF~d|&0coCDkPKP6Mj`+UEq|GZdPLuo?hgX6v4%zsbw_7W{6=WZ_o1MsQ~@b1l;Vi z(h$w+vM^dp2%(dIoAi4D@Y~=)%))Nutn$XeXq&Q~&poazn&PaM_a?f_Dd)VMd}UXC z`_(EL<8HkVt=E1qJ14}=;OcE*zE%6&@aa^cX)B>y%~F`jJXcC(1A(5jpI90zDrscA zlD!13ggrFk)-cjM9GeDC>yj3!Z?Er%ILfq2K0AzC zJj*+I;<0hGb2tejc+H82C7aRZ(D-1JRHT$DI!ne*E49<_wwy{nzkG~rFYYaDl7j+5QMi01Sl=?pVHzES5O zQ;pIo4w;C?;JD`Q_i| zxm^GYW1CBUPo8VnUN2-bR@Ra%3{Jv38WVT!wkJ}-L)CZo<4QTtQ%)x}OEzWU$)sd_ zJTW`_$%kird*3R^KS_L|!!1iUQnzxpG6pyCQt^(=`u&gsxjxUvC%7q}@A(|tizL^TsAS8W_QVF{7KU@W$-0??ufqdj3IiXR(C@y0`(1`s+Rz&}&Fz*4isQMKar|}KCM92Ub6}9e zF0!D-G-(Nww22eX&10s4)B_}{9Sl<pHnb*WnBD{-R?_@K|BK)zGRu$x1Zu47#oVwQo>Ha}1?b|}DTs?a1LqDG z;o+wxD;_p-s3OGNHgS%5$WNJuMb7r}&Pr0S&&oJ4pTHR+|NcGV#Eh(DI4RLGFXR9> ze3qA6p6>3gCwEw021F%3aN|LZO`woMM}KTAMG_q%>SIL)FPZ(dd0KN8iXcI33;21OKn9Jy& z6FZyZMRj7+R4g*fqDYly3g|J6{dEM4?${Klt&F}cI_HjMouHt2;^xNFM?yEB7CX_x z;;A##AFLJZL1qn-wn*mcqtP1*X3vZ9TCjT0#_z-2$yux!(g*tpEQv@_oS_O|sFX&3 z+>IIQSy{aOT7p^30#oydTG7KeWb!Q?OADn~X#q)w6b=i*8&wdZC`nY6xR#9UViOgG z315~Zv-sAlr)+)Q&E&h9iper`feTSJ8DVN(RZzKpgd_7~Q}UpWBjrL%CZ<`{!WWp# zTgf#D$Qu62qIPhWWGv>VSd;uA>%H|YYVvB1nUQa)FdnQm_9nYw2Vw5=i)p=N)FeIh z9Q3~atUW*>(PDd*edlqSg$4$}HFDvBxcf|fA@8@$a*v#5-+MI5GuGR0P6h*DCVt||~ZA(t7QoVhs*iFXKv7eV*8#zF9@3Cyt+YX;ttpnVFfHnVFfH znVGS~%*@QpD!~$zxFl=uJ{{e5ci1QF>%I|wP$*(b4{PSgk#nv;b9_HG$X&qd)9%OB zCZEw9Z zU7UB{C%#j?mdpP{eq#O)2(tg9_mhMt#L0L+?&Fzyni=AFB8Xq_fBYe$kSwgM>ZmdsZ8X!4 z9+&K`K&FT+CYLN>5QF>tGtu{HVy8SqBI3vG!})%guLAwBsY}rIQI-P5Am)Y&mgP-9 z>i6*n@HLcC86cxcvR2t=}<3jq$>PVO2*_WXywO% zoPVC!Glk|GEFXe)n4e3f$)~non8^U3Y){_-8-E|d_xN^Q$p<{I%q-6m6Ytm6K9}<2 zmaYDV-2K}a%%5yZz8EsU{?5H&hs}F`F@gKkP6} z+_WLXHX|D&!~WdiKo-w~z9or_-Idw~UUSy+6>mZ~%&q22A_cf>3WFvUEVe(=y|zvx zz!I9+SmmcP+YM1J&!T!8k6g({RRR!{S0}3q2Pl_xszKTODMX$?YI(|M! zG*sZV2zLVY<_!kjS8!#JiwiSuP**5Q>=w>(q#fCdEejg5QT1%10TdP%oRWx?sZ`WJ zK7zYvdNSFYYl@ZlJXlx?dFiL{3&{HCuvxba7Ezr-;r+oI3JzC2_U82Vd!~byh@#sN zB+%3p*4)#}q9;xfe$7J4lp4n}m#x|Z_>KDUDmaxtA{J0$JSL+ASFcp+=Xd+dapQl0 zep(zmk6}`9nrn!WA07PY+J+4@K_KONeWmkze{AJ@e`KsBNQ=E*Uh~&dV#GleXZehF2>^YO6~3VWVG2cjBZkfnLQAlRDU}9y-X`OCUSg0&m*;dbidjz zMDES3bJD&7W)9{v*oH^XZD5tOSw>Ge@oojwDvq_-)Hn~GR`a-el0otvwhcr{wiGp@ z69ZM5DpSCSZVr+XO==uzO737BA&g;P0ZeXIDw3iC2NU-l?t!?IY45%OG{r?F0|xlR)EC~g0HlZ<4v>UjFIA59V)=nr<)N6rK{nKdvWLi5Rxmu+m%pfawtk6UFW4w9+ zV8oFxj39D>%iah2yNSk?@^YB*Eo|tjp(1`_@QpUwj56k}d#l*hX_j|za{JESxa*SG z+XcGGIX+>%<}4ntIKgOeie<+hVuPSn$f)$NGN4P?@etk+T5VNeU#ELR!PEz~ERh9&u$z3v8uucowF zd*&1=o2DP1$>W#%$p;+PlA|z>mUp)lDYR+qERR#Zhp>tFd^YPbB6b5ILQ$dOapNe1 zlJQ~5--2TPl=VWo9wK4DmXp+LPx{0aD`8<;sfIJU;pl9^#kP94IZ1PButLepM7H}0 zc(eO>uS?5r3)EnkYF_q>8qFp%ou@AdvtW>(U*65jCGRv{=zO)dU2{dA3JAG`M9=BD zyr&uUYzW*$xotk*Km3D~84deHJsKnJ&lBr#>3h%YT^9ZBc~LlZgDg|QKNzJ z=Ys{)@Dq+!3P&5Px`t7hZd@D(>syFv6FJ5riDqyWV%w^~%X~{83N6L>K5V3}n;Gdd zN_q4dC^Zo$5CRzL5%HQw5>n1tWb~PEF9gGnLKTi(%=rj5IQB^lMbOcw#~-+3a@57w z@aJ12g^OkA?kW{bOlo{)?5;#5z6r53Q0_R!F z9TYtU7RE1ibh%~h3X9f)%Si8>vN82a40T@Cf!+RyEkT)V@mkh!XW9X*=Qy2hLQ&{!0Z2~d@ zs)011xY}&8wkIt_Y(mYH`y7K%>+9+5?Bwd5M%KnMEDL=@vL;+*F6l_+7w6uztR>+a z-MaI2@i8hNRB)e-w9EC#&$1XFvK2KJ(QDsP8Kj4i-5mJJTYHIH@ErNh=g@MAInDh^Pys@(KZO=_=#Vu8}B| z)XE17!em`fx{5f7nrTlx=E8~Rbv=Jn7l{vaTqUc%#lF&{Nnq#cAqI$(tlMO@t{naW zjOlPqZ7PU5QqDk#KH3W1a5psimG(NVHy)E~gQqldcqDt-Vq@pQBf>!@{M#uV4${Nzo-DU79<4B3a9dUZ%Ca zGhO{DmpXc@)uw906LrO^6X4x|1S-?KPa;!Wz z4(u>RIwhpa>4`%n6j0h{E&1eA`~bF$#IsprDfj_R3{98|VtWV!n})BY0nV9{I9SLf z{aPA%)W4VJT>7u2@!6v4te-8_WxCEuHtW6Giu7uYZKcD(2);3aA%y;hqz63*)eJn7$z z0mKv7GFd-ik_c_>bUApd$Wo;~z)pXY4rfs4WihgKSwBTjTHH*iAtoicW5gEve4Der zdTeMDnOMQV=w#m19~1bFiyQm1Ng%xS7yF0?5>2-37n+2dT=p&wb&h* zjr^n7Mm~ffVq+jEajb@X66O^u38jtv!2Okp9pW!02xLG#i~c_ zv*ipoC$wlzYR8|plLOIUGGHe3`4u8@+GJy(%2eOAh~b$MS|`Aaic;Es!>5u*XQp0d z$+J1;0LN+Ob|ku6WQYkcWIFIW0m$Z(F5~(PNPps~de9m}VZ%sq2<_#Q2{?or_7&2d zLS5tH4+TfBkaXMmq6j~rOFK&L%Thjy$XF?60W>9Mw4?^{sH6JcO7dE-Id>>#jG1|> zHQK%%h9Z2cD88f#4saIeYvuF3f8(poW`#Q_57T1}d-LQCIZK!T{ode1cZKGpXxe-Q#3u%smR^7rf#3Kcy{ph^2RSk ziF#v$YQNBiG)^G>Y5;ZcW#d_o03b(xQaInK_rFEq^wdtg?~}I?zGIzRTuKSZLpbAO z38q2xn^5fwAf5fIJjC#rYxWhfokHE{q&;-Rs~&ev_RBJFWZC&q8Yf;`+u3gDEDhAbWyxiMhzqja$N|zM!B}U6YT7{K|pQ%o;0;aB!ydQa;PMVV@RJdl96KvgeGjeX&*V?AHcCQ?Y8zw?^z|?^m znL~TNh%~ZwtKK8Z;z)Hn5=|~>S>x^NXp1#If~_ncz01bEV4?eHAIrtjWtAqYT(Rk> zFY&&0sY^`G$AV9(4ia4P>=*}f57T2&B2kZ%1XWp~M>>Lm9uWJI;z*_?j+c`h=+H^6h#o|%BuPP4{mVCQpN(93h0=Qqv@u=?|o(yx$D zV>p4uxVk^=ck#FP1|=d+S9(9?=pr(|X0eI_yq>|@BPP1W_rZRsWM2F0HGSHB09x&O z{_LZ_1GOs?t~bQQ(Yg8Rw`bf1`hR0?Uq62wP2sxJ$5h4K8P!MgpbwDy`iW8&c6G<> zCxNajN&G{IkZRyjEVc%1C~cc(8OLV{Kl)EglC^^cR>>HcEA5_3uVX0j*!!g@0( zTU@l^aF{hxuQS|hOFL;(K{UUwrSLcsEgL7XTRx?=9oIPmp2PE)*|(%H$|6vqGmaTed+J_DPr`Yx*m|WH4h__KrG!mlqg-@Y^(+_gxp}zE zOigvW+0oD%cbyj=9{e2tc~dw(&2;4JAW~KQgGtj2|*P&AcpE-Bnb=5?Ut+$NE zz1U3`T9-@ffs#$U#Y=Y=+h}JR9Ydz_iP`Ua*NcH25|P~~`IgV-(PGb`TPJha=5R!( zm77NN`|_TV*AR|qqvHVl<}Kf|7Xe&PJ%94~#!wjkAP5J-ZFAr48=5(1;9E2DDBXjU zDXMowr*P3v8^=WU;9HX>8hiVB7pz3o9}9=)qIYax6(ldfC_A<>P_AEm3!{UnzVIuO z7YrN{-VdkThuu$!2YV1%Q(o<~EeLk`k_($dX%$Nx=GN@W)9MWtnjjv;{zeTHz@Cu`}q)mOrrb4>D`R{+Wb4IFq{G+xr%DUH9o9%OB*;) z9)`*Zqi25lvOTTCkuIG9y#IbfwXUz=t?7*Yyz)?IuKgB!PftVW+i@qRx%PK%Uk zodegGbIJ8btwMPVJc_)wlRoaV8xvuV$ngrZisDG>`O8^GxA?o+5lo~zl4;+mW`j#S z<(fVBN?1m|eu(;@ma0HreBIsqOa7qjIiOT@2Hw0N!M)Guy)r_tTvML#a~JZUX&*Oi~_22b;|}Y#!JoMH2QZagmmSgLENUyy4L-x zgy9e>Y0{jFNzXOc=JCOJJQ?(NpAlBp-+=hebE()fr}85HJjF`BEu1Ci{9 z*yA03_D3J8N0B6vu0lI1JYCUb3@Znrd4X~B#`9Mw*wLeySR%>A3@XpCH$VxEkO)n< z89rL&%_f1)DHhTlja3S_oiIn>%$gq)>5g+z=29YhR8?G}G^h0?ytE_F1NA8ptP4jX zi%wg-;__mov7E@?g}s*^shpW61zt5DRjL-YwNIHUSsAlF3s#;eXc;z2khDTiJ(?ex zvo^0yg<4sYLvd>%v;5Ti>5rOI34}ZcIc=`^h)WYH1D*!akOh0Ker(H#Ih$HPzvnb9 zBng!-OJuPaL;8JJ27H%s*%eftz zQ;2CC&I7roH)vTR&g*-E(vt?}Gj+2fb0(w=aq}7}a_ziuqEwbBeFRn~wIdFSG<>Xf zRDrG4LNsUG9Jq3xSlbBG=$Uzr7~@Aq2yYz!+VZx?%ma3&Slbi|f6Y9%q8`C#BuzVO z+);cb6vPJny$fE&@Q(D?Ujk>-MAhqqjg&6aw;HB|6ufbIYE;eXBjt+1dxA#5_@K-0 z;+V5tv?b@K$>|w_dZJ0UHEoF&E18*}C9&gy?KXJXNs2?&5*FtOxC#*9?l52H>|-E` zemBBPN3iTwfCNF1TeUCohlhqtQqO7@8T5}zJd=#D5|iYIs3a2#VkK%`$}C~QNt_43 zv2v#O|6u44jkzrD%Lvm2D;gLJ>q1Rims-a1pztJO8&@*oCKe5n9Dd9aOwF!ZX{wLn zjXtFGA~TOGy-_G}yYQ}&;22{7s@cj$WepUg-?T$+r@PaXk2spby%&Dmd`DBZ*cx}3 zFDiM`87qOFFxl_i+h58-?;hWQVIQCNaUi9>~M zqg1ALkXC|Iqb_N*1Z$K}HZP>GterP)tTxRg*3R0Kzofl;Ppyzq^ZdP4#XTtFof~l* zZibhIjB3FRf^;&3bUl zOwlG&YXFUQ(2pk?-9ttQYi%nAELacJA6iu_=`mIqO_wnn84 z_J@X1Tbj+265(LSO>}t;EtNfXS24Ee&(tB+%!zPHV5hF{GEuW1Px&xoY;aT$ zOHMCKnS~o3mTj(M$JRQ1#N_WrFr@lFgeBNKAC|!yv9w0%faPNx;+?79nNPJTIy*C+ zx+O_4aeA=q3wT5`k?jQ(acMl^CoMn8hgxlfHnVH`=hccv4}O83kJgj-V#Jfe z_6VB6ZucAcqZ?l&O+Z;Y?!9-y^Pj~}U@Uh<`v0tB@*hro{-1YD{yvobH4f`!=i+E& z;zaQGp=`SU8y%B>cXIQ8GOo$Y#_`{EOr~+xZHZfNeR>RY;etX+r7i093^Jj;>`&LGZ{9Iey#-bSU?2aFCqLZ`OeEm3t)B8Do7@eHx`61tj)APk)KQr(!RbJ!xv3az@{4eB# z+r!EI$(zsDUv?j_gY)j+Z+o5JpS_Q-6(8|Md{kH7LwoO6Xw<-%d7F#6nw!h?=iEO&clNi)G= zAS0*9FL@AhYG^dt6wF8%no{ncz|bi7g8HZj5g7>0-S|S@s^IMPcqjSgs5wkvf#ItX zm|An%5U#oa&lfOkMh^1opKb&Oa4Oxx!>+Awte&)vrj6&D%Ca3q zK`raxyg5a|VDsi&DcLOE-|62$xXO?nK##(m51@7yhO5n94#YWeLmTYZBGvSfC2d{S zGN2zzLeI~BV8Kk~&&!iYcvGu#s5J~4lT`!MBGNuM_dDOjBL|m>{T2*LxEBnH+@Q~n zD!d-}=MWX=P{j9ZfN6463d8n-(&y$YOK%)i1dO{d`_N>7VP1`6DM{L96?jY&ht8p= zm%Fylg+*a7h4MpAa%XK`WlZy|UhX55HcDQT9k4y#HKLa#FH$KF0l$vD9<__&e7qs| zg<{mKuTJP!DkD?4LK69W-kg-_uRVK~~@WBu}dm4mwLbxt^_E zBA_;#K~b|TDoJ)aSqnaLrMgwao*QJLe&%z+m1Zqi%`bvtKPcp@b}|QS5HE7Ux_#{7 zTA=}BuadOPO?CScM{H)vCYv~<%hSEc3ZkTWXxf(A8EAHrB$ucLsLYIS6F~&1jD_g7gI>@`Ykq9GCN|tK&4P?Fy5T5p`cUp zY`+0gb>JPtN%ALR-Z!LdQg3x-M3pvtI* zuP=7LiOMD4<4-vcJ0B7c=9W5oZlJxt8aWqqh|i?BQgzSoz!@MxDSr=-<#?rMs5e-VK zX>!xrbgjw0k&>nbYrv*jMW~zpBQvZ$#6{LH-`}ApNy#Sf<#)aKD46DSdLP(=BGOM- zQA1V@8~}YZBQGq<1FuLp#DOq*LOtJhgGAsj#Gch5rtZWstG+mcLRyV&MuD8Sz%G>m zD9N!FkJM;YLhRq+*Cn+8$5WIP9YtUeZ<>{8mmU+4C0t||Lpu90;UehP4%Sdm=)$v` zRt}ob;8(@;FwOfamsS=GnUrLGQz86_riUPtnWE`%#6QbeM~8ynBmG8S_{sFt+r{H1 zflhav3#SmtSy-)8JNZ-?E|wz4Fl#eZdF*OVH*)+qOZX<8>x0>e@P_H?SLKT3bgV4$ zs1-*%PE`)ghzj8@XrOftV}koF-jf8Y3s+5+R`ief8)kW6#Lqvn7rQ%D# zm+44p`OUOr@9woAnrG!h8RNEb0iZ zR&^%i(jl{kL6-f-1r`>`$o88*;vYZP_7m@n8DP`HtFW zo@u{SN#^F-n>WF50wVDDhjI6XhNh-jT1+`K7N-vM?`W%q0}~F17vnp)S%<$8^pCNY z4^Ztle(r2saojriZyn!Wb&QxcK{8YTb50be@4oN1@_9dfS5K#0PThEE^q}7ddH2sy zxAO0OMMz1MLm08+VcML<+kR|}+VxeP;kx0eIm~OZz|Zc`IQPJ1{n>M%Fo;ET;>+-k|yqpe`watRJzW# z@`Uk{yMHC~NMc9DAY_uRSCeV$%8oz!(Pzaq`ls~d4%%|Fw=G-?m5L49Go?wDr@3Lm zTgTWV#-#lTd!v?ObhmpG1!@H}e);LqORs|LiCiu$Iw~hq?Izm#YLC5vN;x?6;h=DP zCM1vIejJyK$8w3^YXM<=axy>;;fK#!TRHLd=#&`(*T$1X2=(f~9lN$K(%!M`mf}LA zx~Vv}_J$G{m1ZM}M{e>7bdN>R_Lha>tArY zE>qOJOpuq#&v8}OuN6;oN}6PDs3UeYYOX7tIt8g2b{hj*PKPU9Pe1yODoqsbyNWzF zyDq(vIjlVtY-@TbT3Iq+!+lIes`DkkgYQS!WX|{e3HSlN+Q`3@l zsXFf@;c8Y_dW8uul? zLNLl>XtBM9|GUs z!k)$M$LY=J?q{#TQW}VE>yVtt599p=1?a7oeoAhd7)qy3;^W(+uy5r=TS%T%Q6<#{ zT3NNMx7cC%+=oJe{rPT3q;Y}##ruOuoqx%C?Kr;NOAZC3^5!k@a?Y5Jv=y%v-UqJO znf}QR#uxZJjpz}d(cb$am7qT$-I#}||ohb@M7h*$_dLf>ze^Io;8mbcE~ zQN5vr{9SgQoV!`B(l^2S9GU-eu33QK`=915Qhd4(`b{M%0kx$VRJCJ~yVJ2`d&YicnM9~=1LV(3&-uKj^ha@i|*>@=@ zf>3}K@hnWRLfL`HvT~0{DG^x*=?+drA$o=)6H@bM_94{t5=m9Q_~sH=t*>3Rh&EP1 z1xmE%5@;kqfN{i7bbkQZ!+M)*QYn*HVa7WFBym2U1Vi*m2ipJwDvs*`PM?9OPr^Tg z7+1jVtr0}8(0M`N9ETbwiYdpN?to|2X#DdCngBh0vasO@4F#0Q^&8=rl2?jGTWuRMx##O3>U7WJEO9hYq(($ep z#0*;{NZ7vpHA$Q~6p4WGI%abe zFHR^Vf6Ei19L_^B_&$W0f0+=3CljSZpK>&JFDA=lYO>d;oNw-oBuU)7jtnJ~EbeGw z0SbQJ4>}S-)PJ-`-h_dym1MHS9VnfeD~53}#Q<94K`d6ha|fBM!;^g~Ek_<_pM}C7 zLLRq-PTq4MUVEH?qv&GL=XDX|P|x~C|Gkhq@Q)PHmk8WW;Y#dgeXop)FJ@i!O-A(A zf|CPaTm4qZeOy!HX$V}3_ z9#)PhBXJ%A2mdAFQ809<#^4kaq=&%=Dj6ILDMW7Klu&*l7k9>F?wK*L5kfhdsd8bP}BWYZ3UnqA}qKiPs<#%ge z3Lds>fWWse1+O9$NUP2OX|K65t&Ut|8gY9kS-+HcUo%jsxpVA=W--0i8L%NRV~>)j zX2@NLEj&cH3uNX`V1DQwDp}tGrve81BA>U1ePqM^7j$s|IW&(L_DjEOepCNmseA@k z%KKai4d0w@1x*?cg4h*q@&F5$Fr20GMO_?`2W?5C`M$t3G>pmb5GYx*On_IcT8$~y z)3==2(BJ9^SGv{e8MCQf&#+|49ONfCw(H+)Y6Ka@8l<=DvFwKu1oHro8O!k!eMB*-p#LXlL2<{N#Fv{}b?j8jU*zl4SBjq_Ex=eU*cAUKQpc@%hTLLr3z-Y_zz}L{|C=c@NysyP`9s5=^ z6E}DvYIS8>#kE@W)ZD4@Xyew%>8HADP44%^7q~88@}FsV{{iOpf3D&Ei)Qyc8lh1m9)%_vCwxEy!2VS{ZK&U#UQub#$x9cX8Yq7(G!;_2Wnyy;{@FD_Wtk5n zhkcWQ)Po*x&!_Wqo?Y~9+(@w8b9OWXrXPNE1o^0Bo?DCeVowxOo|xtRHQne_FNgON z-urqstJ$0uk7}}|pZ#f(0x3Hyo8{(9df=A zbho3TUe{>dNAa0|#$;dG98RnmneR6h62fiD*Dkb`((z)sW>U6zr~&-!SNSR?ky1rg9sg%YV*L}s#OAk-i@901`i$5uN$IdSCH5_w zasRtS&3663f+(2#(#tx8Mdy%8!yfUm&!x&$d)%T6R@AcB^7Ycl>f5i}VD4c6<-lls zShUfcpEZ*c&1Ses6bC!%4;N$rVl5#CFRR;fhN+vd4PbR-Gl$6en4zRvDX+9CE#b;c zCMG_d(bbaZSI@n!1%k!aT|q7*5CY@AdDN9G$T^~*=eH--!7)ul6qyPJ_n0u)H^#t$ z;bbXhX}+>s=u?(AJa%emrp1LyiFwS;`=s$)U^!3buM~RHa$z-w^LpMl#$q3nk-rti zMR12d?&>qzN=iqbcj4GQ7G_DfEtU!3ZXW-b&MwCrDBNo8CO@X1(^tz9`(2_DKsN0P zSHxQU44-*!Ge|LdTifh%4E7SUQlGL|c9#{mSQIQbk((TbiFcuJ%#5#Q$9(DDD~TlM z$-=kLvSpLzRFnljVz6^{&~1ywLE#VPLGI5~PzMoD5hBjfED~B}Z_EUA4uXvSi}_kG zfE-Nb41he%#5Ko07Pj6xKmlj-l3I9XsOC7mD=atZP8vH5l_fYf2N|MtA#gHwmfw~i z#P^jI9J%+Aar0J@N{Xw;KD!%YNeZ~C(q1#?S7>~iLz?rpSYGZYf+O)7IlA$z7GRnj zUX(V8XSk1>K=2>jh81d;me{<-)13#}8a5zFF)tudQeODd`_hmLhabla`nYQ0~LQA@Zgd;@eEMl-!S_&L&uwi(4f(pyK##B6ZO|W4yZp|mO zCNNp=O@rXCatFU5U{vM`ru>6?9^nE_2vXU10>|jZ=@2W0-oE-GMW{A}dgO z{4>)~Fo^Q($gZ%=gd0Un6W(Taem`$SNMIg@lbrT!FYYz>8E4jGc=U{An4;p>UC*Qg zwQ=d$w5heIw2u!wPJvzqmGIzrucuV`=F%5q^1 z=v9r?!6gW8RAY7YDvK|oR{<+R zwwJ2W`m>$h?UOpya@;aK`&@L)eRKr5cr=Y)KI<6@<+e$Z!(YwQPo^7a_p1Ewjzzt9J7oBONC8>IhGy8bQfCg@JLi4 z`Y<=@gzjRK&WT+?XDtI=2etaHNa&f1K#v|bjcav@n* z&7PXQVTaz+&p|d9*}YSVC!bao#RKP1wQmy~!+UJ>hDw?_O0Wh&nElW!cp!HOWM}jX zU@9{bhZ`I;&j7T{183??zN_p9_a?VH3dOUKb}9_N_&_%MxyAfDS?HA=i9w^i$hG8o z7m3|8OA5k8p6{(8%Gp(RX%-gyJ6Cz+RgpfQnr6B$?b!BoYZa@ME@>{!G_jkTpv#wW zSG*NQZQBYP!^?a=LuDE}d{wAH_De-nr2V)4^nYyaGN#Y)5U7&Hp^dLO z0^b~K^J!~Hn$=#~I_-CD+})0NUhjXY?DnK#jvjwx&5-Eh=G5u&Q>oz$9pe>;w7h9U z8!MhLWY#!WqMj|J4Qv|r4NE`yqRO^18=*Bl1`&sV7ujlAZk2jOx9qj!TT(>!$4=%) z@`dC+xTD7Q2yN@z08L77OMM$AJ}WMtXO5d^wq0`34*4}N7pbYJ_VtvaEhbeuf%-C) z&7&iHbi*y`7F5#7@@PBo_-Dm@g#sy<@Fxq}hk|xgJeKK_m6Ru0f6^cbHcw zP|>7^y4t=tKpy6=*r_~LIN0Pts}-rCru-GTo;RAzDdy)^J`#0f@3epq#WK(+(e9~o z7va?D=HoRLkwe#;BUj?z9&W|2+1PfiyWZ<1w{LDwc&kP0QAG1}IKM7nnB=r^VKFso zSeAb}e?I8#`h5P{)$u4%1E0dwa5sZ%AKv;{*t-nF1&Wkt2Q0^?47Be4dBFdCIZSy$ zxq|-rHLq(cf&>H?u~Bb+zC4)UbU`7d-Xhi&B%`5pZCp8v!gPQI(h$CdZ_6OG}Ab3-rpv ziaV$EZ|AJ*M&CvG{Zk&iAD~umDJIMF&j)dO30_@R_N#9#BzE9~P5bH>BOfgBO5HR2 z8(%E{bNhb1@$lb9K*3DSCu+?l424QAXZp{Nq<~``=HJC#6}#BulW(Cr4T4LFt*7_=NYSJieU`7$p&W$ zm!-CZ$-OraoQAF-#8Ql%2z5Qrg9;#h9#fNyLXu8dVv7gYR-P@U+Vs@<`DN}kgl<>d zhG#&&&OEp9kMtrb8VE-I0#o&HncpV%*mhTDc;fcJVI1KN&Ljz(kxgf@&lHc&d2m zjNnE5DrgM0-xvEJh>Q?EOP``Z5c3>uB0~(=P2{f9Vriy3RN*#t41;Ldmlsru8bw1Y zODfj1X*uxJ4u>Kvxt~&^a`~(bD)tI!jh<%BkPf*B08t~@$$2~m+hTYlYMDGF=qQ7b zUT+vtN`i%#P3}zYuq0SHP}gsn zMpyY{bHgL5QdK-D9}s}xd|q>3&k(Z^>5j*_>JZ%sD3uq;z$;8(BI<8EmXB#!hU;D2 z(ImmFNCg@XR1uDENMkEMhw>-$o*se-R%Ndz2xa z{`^VJ!r&i1r?3JIhEmI}V_?+BiRsZoBw(~{L}3Xeg0Uh=0O6++XKgGT(zp-pEef^JLxE@U8?r0K zC&4sLD#C8Q%u-EkE1@=Bw6tb@;I}=Q_e5?SZ^E9V41Y8}GG?t=n-;Y+B+saot-#u( z)8Zd-9A~{BLoLgkKSBoAtVxHZSy`a}vU6#JXT+qwWu+1oy6Om9LMF%|U2w&asWnK4 z#>N}}-LQT}8zCH^1Vt3wl&LP+|6bfYFkd9h6cw8(Pfp=5 z6qgt_OS#wBBFSP*h$F7q0D)ZLKtRzPhUCnc4fQI))Q4JJqI&>&t0;!^gY;K8kz&#q z1H{IGxP)-`Xo4V}rBn^-N9bXAGRe0ltkHzWZ*OWB<4^30hPI@z-1b&?K{f0h7A&zu zOFgawktCVe)sv%B@*1Uu3k8ds`{U(5W(i;5bI~=6SYOC;XISZ)Gi_0uc**oe1X@$x zrXDEe;CL3uiVq~%NXtgHZb=<;u?)##D}L}Erejr%8$UR-L{wCeaN8JKUMDoS2#1%6 zOc2hh9$FNfPw;)mkAImX$#p(oS1S*574X6DHcreox!b67tT6>8QX!K<$FyL~N5q*oC}3xG2vSQ6kyy-%mx8F$M{f-{M+;w}moJn^}Wutvjj` zG$U@ZJ%DOuJq(*ziu8^x_l_SK9zoH@^=Q^8?2`q*9#uiHw;0#Lq*opI0|-jyt!&^m zc-BLwA{H(qtNs{_Mm%UH9ll+_m|CUU^*q=qp1ouylNcmv&d$>x zOO#l5Z#c46C@h2)o@->eOnbF9!NI=dwn8l?w@EaZ*>-at6@OKZ4m-ZXjmlRKD?7(d zXF=6Z7w?8R-hNf?6{`J5Wd<4Uv|ah z_Yfo>m;UMmBW6{jOyWftzB+7+u617*h<6Ff^@WG#;HXOm2l0F`38ydP<2La!@1sBM zfzB)B`wdyijyLvX;I9^4nYlkg-%KA_w0`?Fl_go2fS3JRv?aP3f!{^pa(%1S{h8uc zbpOo{hX<|PcYCt4|7hdgkm&|Ys}%C?$J{Y5DAUodbFK0Q#W23_^CAKt-g#NT%6&53 z*7|uEsOnCfqvPYvFHe#>d~)i#y}Tua-6o+R@5HCp^xB?ZL=QIdK4vcH25!%L)1FWK z+vr%#XCFP&lezStZ|M8)gkArc)cF5B-;?=&!S`hT2j7$VZ@wo11Is@=U|9a)0mJeS z4;Yqzc)+myEnWU!@qYRHqx_RTD2()ffiM|azwo83Uq&Fz|H8y%W?=vFon_+q`jB6S z5&v}{P(y1wL%M&~Hi7QnOk)g;z6Lm*zFcVj`X%(2myDgYu!*UGi?y?Wv5keTqKmbO z6Rne-HIeieO7y=ci2l7`{~OU_;-F<`{TGu7HWpfDcGfS$jjw32|KsX^0YUWtk7)g! z*8gm@*xA0^gjndA*a=wazY^+SbBmdlo|%cB<1cd(dfG3~ng1Hz>VHAB80gvl``r3_ z^Z)Ne>&vL;UvrCrmXU>p?F$*h!ol>9tN(B0)_;uFzaz{1^Zep}OCkb>uYBU5XJBRi zGPq&-GJE-dD6^RU2WOnWA0z){X8jxMndNIo(*H|hF)*{!GB7YRva|l}2J|mi{~t-L z{}8NyH-P`YO02*9qF5MN*ck}EK+*qNvlv;wDm()-2O9zNmy6JUS;?|@v9_lBGUoap ztIEG?r2bFN6MWqR+rK9;P4jHV61Ude{Q3UJy3b^ruFvq>+YoDf)S=9Z_+`-j+~Ow6 zVLsbmy+~j2$i(uC%FN6ecVq-pF~f5~#V!fMl-~;dv!_@e60&j>#~53;@8^Klpv=Ou zvKs!q*CLhNCb#jhq9+SzO3$+w3x6#>i(_fn(O&{qOe96!48H)pGrs|4v+#akIMsI) zn0@`==qmn#6SBXYzdD!jdf5-fv3@V36KlLx6c|O?+*n*5CNhDxY2RUeTv3?AH)3k? zc)7YDxPMMaaHQ{mq2L0H7$;2A^8tUXzv=+DhK>=x;OptJlUaytH)I zq$gh;8-SZXL503;G&k$cdYr3}cPPl+8M^p+QE3tH?tP(pWS$izA8 z;ppdz=n7)26Q$^q1Oh(Qa)!v9KliCQ3%*t!~N|Q2GBKkGv&-mYO4}k$m4vThhkNP$(K))>SN6LY1@sbU+*Sz|zDmV|1 zYzl%R$OmhojIZ@-=GWJ3A`vis@Y=AwU_A1e4laTNwh#jBd=U2W$H5_# z>}zZ-A>IzTi+a-;dnP=>+3g4F3?`#4avRi*G0bFFBsyo$^onswE%`bQ60u7kd$kzF!Oj4AnmyG;Bq z8qb|vNO9hpcd>oO8hGXfFd3hfygv<$TPDG`N^e|lB$E7aMumuQ!V9hz6jy1Q*;MLV zB)EikRPjG|UU5u60vj)3{I-c-8|n#DJNtqeJ>=`#Y7sYD`KSWVMmyF%8+t8ElfHj2 z;kRj}jq$k9AD~eJ!*xOS>IG06{0s%DZ2`)T>Gl>?Sb%tg31`Q4m;?5$C1lW{G@fop z0RedbEjEiMzo7Oa@k%>!J$j81iqU^v=@%k=aY6mo35u~JH{lAx-Z5;FD;n*yWqNdg zUrp)dUTNI$GJBb;=b5x7Pq;9b0OM(Qp_-T{@B5Za!qD zI?b%oD%(_pePv6ghBK}EXdSju+?G0cFUk|ybfcdKC!HdK4$V%*CdcK+6B!T8BBwQM z_@<%uu*F#{@md&0mBeX?LB&yW(9y`hfj8|wy zS34)?7%-;@P8gz{R&BgZB3eSM^68J%KoZxvNl#%NwCl=a{fUaK;)^m3)I1}u~dT|;b zFEaH$|5xJ<_5v0e9=W&*89No8>-q+nm+3fJm=S7>@Ni^~9S+P0ZeN%0s)TWRbgHrT= zyuTh!rxgMhHCU>4-U=vz{gf_N=8M0h-Zc-YIeq##Ge{(I{+UhhD7jdnLcOD53J9sBlXw*n71^NJ< zJ`Q-?bg&4{8gDGky@N-I2S>3%OJAVRNr<9XeqvDU$*?uT;n(;?^sAXa3sLPBgU$`$ zncQipQ>TIPHr?c8-v$a1)J8^%k~e>Evey4Of7_?m;7K=gWT~jyt7A;00G$fSDA9Ui z)3Dhwo*-4tl0mJ>FFq!c3j1-$>3TJIB#hO#oawnB9nUb5nAUlb+NdcU8f<#iA~>Ws z2$2wKYZ&Fiqgu{~=V8osJN{mx;!M-(lLP5WJTksdd2$*#CgTyACYqlZQ=gq&`?M|A zu=At!B7sw(tPO79J(4}b1_j>vC^XTw>o2M?|14OkPuzJ@US{AYa6cF0L^m35zPj}^ zO6J4;xC{L_TFWU5Wehfm&1uAKCe!dfZDYkSCe;e;7G!6VE}4;%eTZkF?= zY=2h4?u+^}{?)@PB5p{I_Dt=4(P>=;fUB%h<@Xkn-7GHuGxfLad5SB<=lqi4Ttb@; zQdyJSwAk0cSoHAfkoZw=R8qMz_358|K6NhgL33RE^SZCATA1$0b3gZ&b+Se5O?5Vt z?~^YRgAl{2q&K=brBCJh^`k3-pw%ligeMJu2RphS9&M0FpMfTMklf#R(GssmE&$&OutJJm4CW4)FPM2jh$!c35Mbs9k z7oSAiLlfm;J+#M=1BCb~^PZwt6o%H#+3art`EdQy9RMDGFzKR}-KJTNpsIzjyGPkE z*8tv~)5vtWsoxbhFe-7k26tKGH~~E5$usDB2aE4(`YXoI_u&^J|GVsMUsev2-pl!o zj)M*d_1fPZq~Eo{dtPw`r1B2>Y$b#ux2$3No=@{!MiGDidM>5iI)oGuY8oItySN>H zLJ3P8{UDy0D1^tV32N&XtWmpR=w1x0rd-pVO z@7@FM-HMYNTkekxWhmg(08~Z;sD16+cX(Vgu(mXo(}`4)x6&Ttve=e0cCZWLxot-@ z;t=zEt(_R}B;r%_scS=Z*&paDQNrHN-a%jD#Z+}T;4sV8T&H(E?lP^%hw-A@C-{Z; z=dta0?YXUZpETkDW1zXuiWc1DE^kpLc|^+%q66m$YYh2R+d7SH$5%8^+~zl3vmW0; z5l+;uA;f}noeQLwA>pMccGLp~?N*OJkzvb=$@t&0a|a^*BzLlFEQ@DAx}*%>G52c|W?Tn8Gg*_lHET|%mm~rc%)hK^i7B99r=@(_Akbs*u+^C z2$^rud}=@5PeH`M5ujhq$zI_cknyxum!V)EGWx&bWHH|72?zh&k{B@LSQ*8WFRKf;`E+Y^LTjo03T%A{m#ewxJ?zqXZ1cH z?0Q4FE2EAuBJB>+;42NGxY^hJMb?{;Oy5pFD&xxG2%!gddBG`ZLUy(%aeWh^80PU1 zp78w%{TxDS;lbBcT`1yLw~6t9WQcHCN%2^Ow+@~%7scU0IZTMbmgX5bemp&`l^u+* zH&3xcWMLsuG>k>c=w||?3A#8@h>d&WL_X5CB{$mnf6Q{wxH9yKr^4eLI zO!H|!EJ`S`lmp(@3$WQh?@*$GwN|Srvk^mLQR5{26q%b~M?f&FNOqOzpgho&IE}GR z;&N4hZlfx2;M_at*Ip(H)j0;x-)C#WP^nXd21=9=uI*5VVuIwOySCf|Ny;pBxB0rT zHM*p!{K~J5KBd3GHKZcF;Ocq$`X~EjegEW?;nI0kd79wbxUH1Qu=jR58oD@$YDDII zYH!>#C6BBpmfks+_1niirO2ttlPoBBHJN=?RFX(_Ub@K z+=EnadKIVn`-N{O2B+-VGtp`_3@X%}$IE6^LOKq`Ot&pnxu$KT-H>g{#u5pSE+d?a2JA>6um2zO@1*xTFf?C~HSGb|qE`;t|u8++cy?^QW` zgX2)V`qX#~1lu&d4$fHU8`p|H9hMBr5o;)p5z zEz3a+0gs|SGKzh*&TY`@Wvr&GvEa?nud3s`D)jNyH{|2!VCTVTJvYeH8S`mrjQHB5 zFq{1TDyURxoA@&L^{gK5+IZG7LqVWg#0o2R?Ueps8`<`1-GaD;XCBXVqDl)MlgQKt>6QDVw4^cWC-wM;Hiyu}5%?JT;Y4B$YwOZ%?ViIzmZ77F zKL1iLw?sGWDvKl&Z%$K4`a&`bN|i~=JC!Jf@*MnKm18#Z%OvsKXdk|!Tm*-7Rxs-- z2A3$2`Il-iWopj=9zm7anpD%@#fv3jFH#~D#*pmEb*3VR!zembVBQKYk|k)(A-P%D z2^oa=<$yh)BTy9xp^i8%&56u6Ba_e+&|W;7`bIFLpaxOF>*}WfZH};Hq`fzEEa%UX z^cX{6zM8XPi$>r2BdWnLiAn`(P+0lU?ld6igS{CMC|L~0+lnP0r(^sIpST=ASjpRD z!m1oXtkqB^No)f1`jZD7hZP}{CBhq`S@a-;k4B^fz(J}33vm#`4_T_W2zX(hv5YB? zBt48B?b#^o{E&xaEj$5u&^k5>;#{@lR6ZhE5WS*-BMbgRE*P5k$f$ ztn>Qw0odm%U}Rlis-@79t!Jw=O&!dMvL?u?S6vDwb}Y-xO8VWFgrtxPWcC+3s1Wm} z)KdHPI=;z}y$DSNz6q;lNxwCuXN_}gUMEwN*tjAPyXun8x%%Byl4#cIP8)`X{s{P2GG*qzV1HZAZ_bb^9 zrrZDjXi8zyG|Bq=n^U+I7u8>y+l&Pk=@Pc^NR9 zmbgH7*um5+B^|8$Gsxt`a(&N)h^DJ9Ck<-u#@6za{B~NHbr*K(bOWI6c-Gd?sVa{( zT_7SYbn^R*Qjux@(U8w~$bIs0Le?q)s?WvbRKsi{<#R~~n5!p6B2eifl|bL6L@?t^ zZHyE+QlbVW9WxqLE0dCM;uSe%{T`A{V2N;dk`%IXqE=R`qWS8()Y_ET@f+^7O8I-W z7_iVd6d5$Cq@lqftN9{K`XvZ4dJCb+5mbTB)KPq9HCfDiCa*VBPXO;@3g&&;&E|RJ&ZqRnjQH-5fbr^49bCevT zy5i~St*R`eHbq$zlk1lHNq*QGe2B4+amZKeX{YjT1RSS+LjDE?S{Ttficx@@;>hcp zS(m~p3aK+FZ$i)xZHX5zYHEYQ7_v)=B8%`);DlGXI6=D@Y<}f|0ri6VT@^|>74ehH z5WuU-HA!?vhzU~4_e;g{bQsua{U1A^0fk9&HE{1w)^$)uxZX{rvF@xo!Q}3&f3pLs zWXu|2r`nKh93z z-?DH6m6tIe!A^9^pgsZWi6n-n6cUs^lZ1LKG=P=FO&)WhFVzh8g%W2c)jy_jyffll z$q|c0&M4fjAvVB?yO&2W(kE4f=8vACc4TP2=SSO2p|aBJ!?r09fwx0!B%ljNs|801 zGzg!`W5AfF8W3hm(yxG;+rT_(_FjXroolbH*pMUt`h5Al?_?doJ*LgM`-7uC8`*V6 zacg1+iGR?JvE7_!Qd`i;#?Lv!UH+avL+3k|7&PSlD1xZ{qkb`aass9PyXZz@+^N{+07&+MJfryk7h})R~zyluaEC5bMVrE8QXPE#TOq|3_9KZt}e_j3W?;*qgA%wRz zv@v0i^NQArio^0HFiJlUA>G(S~xC3HzeRO#w?xc3*G!4LAX^b{wA zOOJPt$ESj{lT*9SKOrTmdVg`UQ1;kp!mU@19WMGgPPD-rr`dJdaSQwJ_*Zv2Nd8af z*YZ34)cHxEgf+LR<4jcCeW;$sZLYkwa&;nQUf<$;=>u$Z_%i=dmN&1>_))pXIh?_mRfM{o4AqW$oRKIQlGe%zx;yXmXf z#lOvCFK}CaBtPRBz)~@?wv`+8Cwg~L=b!L$hmF8}XStG|d6N<1U{rf~47^Hz;9I$w z{LJYk(X~UU8I<+`hBmAh2-kE4S6`Au&%nq9o<55{&o`6GqvNc_i3eC4mb5BVfHdn` zQq=YWhN~z2(*1Fomw<2iBCJm2{G9Z!YN1gKrltZIVOp`DRsbJslJ}TP zZ9qf2;7-Uh>6jpVcw9I+U*dTz07u6o3p-*h72 z*AGGC@8!J`-9=eV5d|hO5o@14ABeBZY)kE>Ur+Cw2FkU1otiyn@?}n=_>)J z?JQcLmUEd`>S*5Nw!Ug;`PgW-3(k#f%XF5r_$GW`c2$+`K;k-6@hf{MaNBj?O}=hl1Gs!`h|cQuiA=| zy9Mf^CH#X1(nvI=NDmfVgz~T^<$_>Ee5``3RYw&G@Gee78oS{CmJc*wetwDdh<=M6 z%-ZCxu46ZP!lF7I#elq+M@^oWtd;b+n~MLq>*Tiy0jo)HTvGDEiKxIE8rfkcGYDUK z2ys}ZRkTdKcTx@a+#5ni@-f2j*s=5cq{EyJSHrqa%0;4p{N^HlOOXMoJgX%d-JjhG zxP$43i0l=+rJ&g&C%9C9BLy30CV2unJf&unCjgsd(CC=YT|n+?+4D;eWkh z@AdR&DZrkhF}Ve~ZpB6$_Mb&Ugv)QWFE4wlM)q=(&ZeBpz^mYOG3~RY&JgwKVZ6MZ zE``-bcAU8J+{$pt+VYxxP{|-FZT*_R#g)62$aO-6WWInB9Az6>xY?XF?y8V*x-X6EQ^bYFe9wRZ|XQT9+C{CQI%Yd1#? zZECnWDJ_Q*#1(D4fNZM&v#uyysZ)u zQs%8)ncG?MFm_ueM0$iNNLutIz62>&zd7RTpp(;$r5Yi0PQqbjA|@VF53zegY}DHz z=ReV_vtW0N5qwFlOe4Mily;)E2^Lc&Jx`}ZJ>M;qD>yPDeNH$iL0QVB zhbaxBMc%KYk%a4!J|>1)*;-N$5p{yq6fbSa{$NggfStm#LuPYd?Vo?&W!TSm@ng;E^$G?+{*T z7buUA*G(3c1R5!Qtjk|U-Td3F0ZqcChu{EmfSK|0d_yU z?2OHIF0b<^;T(RLq5rTO^g9}vo-ZZg!YZ&=aq?pku}Pl%CQ(EpbO5{C6HK4X@w1XS zhD{Y;!7u`h2*I&0TN5T~AOylcm?Y{RA?zdv{4Gi^yAabHi|Ef!R>A(-2Q7?$z3e5Z zC}E|&)rsIpydavNcJQ_3ed=6+Z8v>&m!OfTP@y+y%GPvukZ#h& z{@loC6YKd$`pS=1+mEgz1fIy^lGMVL>YY1GJLz?ei(KSLl=iFkZ5Pz#a8c20p#b`b zHawGHG0H-Ki$mDRSXi)Nz&Hh-Z(1EV_(D$rj-Gb#r?6r(OM55-wA2LU|yLGAW%!6Bukvddl8FynGu(mDMT9If|JvW2?M-b7rr-}_-HQ@kS`hPUg} zyzm@H7AY6nV65(oxgry3KetNFV3(>0_z$wS8b5NudBBv%S=oPEg2lndn|1(hBV`^r zb-B57Yr5@|ZGF>!8R+HlFgAUr+xh{)c7FqM6%a}mJ~>6;AA1g~c|%{{tWzzxWMTlV zh!iFcyAim=ssWmxOFXS8Rz~c2UHz#Y`=UFsP8zWI11yXDfMzyOU`-Sj+hhT}7Rg%& zj=`=M?RN*_r=Z5Tyzn#^d~xtwb;*}P)EG=>Q0{glx8-SQ(1$P`s5bTvG_<|7l$#y{ zxlfk%K`K?T_ZL3RHhof8ZZB4|qEi$Snw;*Bc7>dsDgNU0=4UYY6Elj+IjLJ_0^5zG^B62MVX` z5u07(h+iOSL*Gcz7HG@#fcdg7AVF{Z{(0xN8W16su@C`iYYjopfp((VBC>qLwtB|bW56W%-6NGgX%F(#~Ch=%(3Yq`Hsy<2EfaJqzuswLmn z)R$84c-NW|(&DmnbF8w|k6EK-=I5J0tJVoHv*9>W|Svz6_=iY*Y~_SSG6P2Ipv_OR|MUWII? zy3kFW5Gd(>hII=RL4!hkBg+;DrjFfsl~PVWW_K~5ubM2|3>NitsO2lO7_?B#E8P=| zO*^ub8nIBW0L8#0ceGSQy@CVIN8^N7$>^kuM2bV=_h8G;`rvZTjBUIri=r=zmP)AU z6s$YdcS%O+e^yJo6Bwq=Qd+-sv}E7T6a5y$d_}|C?XZ@|GqLAjw+r?L-oke)l2ML57u?Zh_2;p6deoQ3h!N3S-TpmSOPQU;C+l|62Q!hp*lUFB=lFrUn#dy*j@iFa zS&Cx!0lr#$q$5lEH-OOu8W8nTp^8l-PNu5c2y&im$XwzJ7) zz4P=&kSU3Wr7kBPNq=VohsXz9ofZQ0E%F5i$)vo2ua?Ofv$XZ%1-dn?(>!2&eekbW zonjz{XVV7A{RL?gqK_czi}QKSdJ@FX>l~7Eb0CC?79h`uF+*;fsyBl)u;xm09!%%q za8J=Fm?h`d<#Q)lPNFum)g3>OjviB=mlC17P&jiYnPPpN^F7!ad8hd6?d6WUDjt^c z-`iaqW0QqOnkzgd68Ee;%kPW{XS`9$mQtKyt8>zRYfGyN^{PwP_W%HwQ4E!>gNcO)t0#Zc={w-3?{9dTqb~xX$fVueFKI^U%ty>BDk4L3$ z`+TvaQ;eQB8QB)Y+3Amn%=H3MQukhi(w01t&07=XO66L$W3*~Y{a-qT={fqhO!CYR zfKS0O(N#_2Og}u6gz9wId}BK=ym?}eKXgK?EmIgO)TZHwv5+v>SF$mi#9W+Dj-;5=QcK<;k2*3>B^N;9p$CL_Cw9K!^`$)sL|9L z+{`AV ztldHG@pJX=Ddy;KZa=lo6x~a{%!c4st2360Rv$dpNW=75%F(!Fh&rXcs(Rh>Vr&>s z=Tr`5?j;wWDuO4z_Ewg^4SsPeYkJ$(b(Zv0=AGJRLSNCX(S$<2>^ZCt)bWNUc|MsR zXT~?o7=;F)$(z@B*qln^8kv>q%x-cU+N2*ip_NuHaAE{y04Ihi{~94>+Khu{<&YIv z7+{nP3Xc~ys+k$|p+$#m1CKt!73a^c>l8#he-_9{s+)AFNh^JDsq@38jnmukE|70zi6-{h zqu`Ay!-j)hi`N2LM!YLZaZj<|)S!u~SEOV~T1V?GfSo11C5|_OuUPE4GDYQJksKZs==q&W7wj=D-PYk3DVjAeF1*3t(0cE zSYjs{Hig$SP;+g2Ar9+yi}+3O8IUTIWsNYTL340Q7C9;r)lC@ewVr3sx}5kK5E!_6e_ zLxEvd*sQAP1=Pp#WS*McN;O)kPk6y53VMi508-xik%JE|2@BVId3t_$(I_B5S3vr@ z)9}?0#ZO~!qfY>G>fLJFws)LAN114EdtR|m1j%6VP~1(V@Rmy#iQn1zmA#-hwD*Iz zZU1V#O8=w%*S56Pn}pY6t*khFfqDp`o5Cs=96a zkgOnbJm!Y@H-tPSpYdh`5{0|>h&o3 zRhfCnacl5H{z5%F^CAvSk2>8|h{a%P_;H7Ze_1*jIP^DXcFj`IqyqQ$9k^dibCNEc z%kX5uRdg#t~ zrk_edxYy=MaX9dLr17w^Sk?}Qs6)XO(iFKT<1Q%}NwYUL&cqR~{s*Xd0pW$Dv5@#O z-waFwV?cXBn;#pru7!ED5y)ouVyFqgIo1pY{AknLtfJx-K->H35qg(h&QKRu;dX8U zA*5op_L-Xr85qF{!kk7TWlxxT=8JvI&3c=jm?S{xfLJ!JN+LvBEpd#*Me`c(%O9Z{ zHAHRtE^d0mHHm|X9W8_l$ThkIThiA@y@sgE-C#pqBP4SFG5ZjWCH6)jm{n>LrBU4Q znKDzB`jgc{d!%S()ELRR1a_qSXv79I-9b!WRUoz?pR6JWX0?FGkkbIOTCSHYKIdUg zS}fZzVJn22F=ZGfW{s06*iMNB&!{3(kq2r%7kBs~*%M1d#g?BMFrx#fSr|Dh zphSNrFhGtgp;R*{5!J$p_Koru6o_VPM3oycEX8od6UH}2Q0Q;Q=J2#e644X92*ioc ztuA@UJB0UP^nZgWNU_AFV2$+}$+pCij*l7*1aN!dz8SRJETy2vl0N#>0KGw1+1GCS z32NJE9B|fRAb%q0xY(tiaDUUkhR%(81$Q++P0vwfh11Cs&=(7~Yp>x|j$UMal)6Yj zu+LiN^f18R7d=>H9gDNq6}H~4wr(5BRs5mJ6{aSoJ$j%azN`aA@)NVi%rgzu6`oIS zV6^sIyEGGF&D0mskVW#t2319=Me=q?w&yRI{q%DcB7dc|yr@C^Ev-erF`b(Hm(s0R zMN-*Bn{*RcD%_nMg|wWgwbiQWX}yxk6~x`#^=9;~98N6;6*MPBL25g&J)6Rh~uprM)# z&zx~yMW#gHLttV=*d-9A*u+q=m#2zSvC-sZjv|F^Yr2^&ZqQlP( zg#uo*jt)>IfE1_5r9Pq|+^WE=5yEQAeO<(rf=S)jmB%b_Hu@!O#15W_glbIb?<3?0 z>pMzI-(<7*x}{g45Y}*885gkIZcJl0tm?=A%4@ObHMUlJYiMWh(A{A+ZMmXzH z=6HqJ`ec>vM@yZO;=|dC{MT+#a;x(mRA62U6fUZRkP<#Hucae|g8TMeCBQ)qb~iEm z;7n^*3W0FVFN#!d>0^3M>(S;e z*yR0v^=MB9eQsAM{&z_hM1>uHnL0J+o@*eXJ#+U5Dbn^bb|}zpLoj7+L=BiOT<>qWjnG{O^bYfk2pv9l*%RLd*iZ zUF?j1K~$hZ9;k2T;9vpD0-4zVs40PH^}llG%q?9kT#e{~?3+Q}!PHL6)WN~j#?p?# z9@y~udxP%Z)$V^m)PGXHyVzTs+A)YK39~aXGMIX}nA$m8+S@t*{fe5s%RjX5jDUY( zr2ix&{D0L&GBMFJ0VVDnK#t4??DyYGz{o_;$;i%0%*?|2_p7>d3LTU*VYcv0g)Ut-OHSy{hju+1%`vD$+-8YV#EW517 zompiJ?U~@>VnoXV&+$^%+p9YKS<}W<+LwiWGy}h3ajK)vj<%umPOslz-|DgV;5J1m zuKz;*%B}Zu5uNvK9T%eJ!<4-}#bv^q;QS!we&js3UKt?P-WKo4^x~iE&VTtH4mCOF zk^Zm}>;LBbup}sN^)d6|J69l~_}wi^Y8d@N3y;||SNNC5@b63L$Ey|HsN{S4CqRtF zf{9Ypx^D7m1CvA!GL?o+pFSEiwLa4k8+G%9>llK&w`n8Wi#uwbfe*AZ1iPLa;Cl+( z7EpzE-0*S(PiERMQ5LeXw(}Kk_7AOwx=b6r*IbgEE%+iecrI#Um??tHJU)-j;QtPW zt>yq7-O4KCqK6#vdU+wIeuo}axQAW<`?%Hf!}o4q-v9Y6|AQbw2J{2#!9L&J-@haU zNh){B`mBJUTS>fRQL=Y>mKR^o8s2|F(9+fCE&lBXKmBJXGbcGyvD@_g-uKJnUOmzV zH7a+d3DPj;SKhvDjrWdX^jXE{>rQWaK!@6Z+$uwg&u`4zeh}P!CjrZBj&l5<)&k^Z z$i?E~#t?mwJPP=ru($y2^fCh+IOU?+0yWu*gPei)rep_bo%?!7o&cn|JJh0J97cqT zTh|lIow7j&5O#oDT`>is9WWvTXB~hvD@GKzxtp6m339a|9iyu>`HRo?1`a&St+M4y zUWUyU9;;{chj*m(szv3z2oz3y#mgJJy`PtJb;oocznU`g;wpl_tYxy)*{@F74ZhTE zpjD^WLK3-aFs3aNEz73|h}BP(3@HWu0%%{p0GK{6#ZD8zr@B;|PXDsb)nm*-jNb|0 zDs@!q5B2Rr;?ZMP8`?$sVZo#&L7A4>YxjMKbVIHIu%P)OGygQ`|8{%P>kBWXWM4I3 z|0}-_n~CFxfZ-31)CGJrEA5cX89y58bWM(LV1nPED<(+4TOlOSo2Rxo)66~|%&rIU z8=#LUsP9uc;I6M9ur)rC(C(%UBZXy6nFK+X)n&fz!&6|tZkr$i>NL~)ut{pt{fn0( zn>l#^?bz6#Uk_eKGj-11Qfwp=^14F0`#P*U=wBZD4mb}<>gU$&S2h>Gm0UiRRypr5 z5+&{N5;$_nBMmeyXNP)J2pPX!+rWO=I2PxK@e`^V;TzgLdXj>|#Pw{%9zV;s3h@YF zKo-Ug0GB07W~eo6PXsr?W;l#7i`(BEY&;eY`2zNw%uk;_Co9R>%d3$XXkJ*9cbt5C z4=P8}7;Ip)5#0YXk9@CTPAmbKZhXfp=V=&;?0E)ay=JoLX8t_Oa(@nGX0C)8)cfQB zDo?}fiG1q2%EeRO<6wa+@(r}~H~9DdDdjMYl3TM&!bq4;juf*tSPNz>@iM7MenIGr z-o2U`#}5M|>Ai<3|fW9S24XT&tfPcL-%lk^9=0*zbQ>_qo{ z5Frokr*0FiqstxhR3&8`lIOWH0Kz1(t@;Fp?YM>toep>1=T($`Z3)Y3Yh59~QIZ?# z^uh%jkdUXKi{%+Tbe_~$c7$m)Ch=oKOX!N7t|!%4`v#)woqMf^VMo21El z@tUL$8m5Hj6_jPm@=^e1*+uGB7dmO~lUW-FjjiYDSr9rZNeHkEQifZSv7AI-= zgCNI_*wFoCsE4z)T&R}j>Sy=k8(FRt;F!^ueml*H=MQyPA=8my4io=+c%W|D(WNvc zb_Q8{+MsFD+cyi1Ben(Y1;JmAT@L;w$zej5(1C8D&@9F&AX_^t<$=&G#NDS{oh}u_ zxUybRTq`UO&QIV6+6I00^{^$NNLo3v5OE&_v0I4d&zys?|NETVQYlQec&^5kSs=My zP_=-@>8!@k(ywHyIeID~Q&+t+R(x$Obt88gd%EoF@I2y??-V9|1RPt%S zpUt~-2e;dVfffPR1wsQ=$=#A*Lx%b*$>4bt~@wuiE77(8DPqT#&TyIz# z)9|<~J&ymZM{Tyl^8>xS{@1E(%1&X%Q+J!xHLfv+zVj#gz8P6>R?r5q!Jp%qK)*Bd z5ad4U0MP6x3yVT190xE$yT*V)2@dSa@I{1lNxgwscQjf%I2IvHFGSgbjjDH4xp4IL zRWKyQRSfgbfUMcqxPre`9*GTJ5S!=g0&339IVd~g*)Q?Oks^5b7>Y?$gG$7i-%X|y?zon>cdZ^{ow z&hp1=*-y@QVYQ8(OWl;0#Tf4NIa7#7AFpN)ODk1Q;Ky!E)M5%7?wugk7Pj4N;I9Ml zlR5VvtuK?pqb6a2?2%e8uHk1l5Q>PrF3YA8eH?S}ypEMlT}d~EGscyrrithiODi%M zrt>RbMb97R_=gR%?h5Vt-Mw3LX<)t;9@Y<~{;aQ>xgW?%UQi!WQl3XHET@x`mQzif zoor6uH4jtY_?&B(q#LyhU$51;2+gT`(@pOv(MiF3GUwy!CoSYO{Lx=Lmv zVdtkyH%KOfO3igOodP}tU$ropd>r0beT_n2McGLaJSqbGGmIZOHH;7HWzon_x4;1@ zCS74=eHUqtN9-S?m=4f^ttt2rViGh6>6Bca1Rl6;r`Pa(;DnsFQqpa~kfCx2wlL5Z zq__Ay^xsS^?WGi;ST2?$G`{wOT~Y!YDAK<*xJ*0n376Hvm}5>Pgt3K=kT z;?#&Fs2`pO<;R7O$&7;_qRgt-C-@9t6UGAyl}~^fbzQ%madu<9BkQHDG`D_CTfnir zEzdZLDNkrv-PrHN904hb>y`Ee8t4l5`-LR-ayQGV2f=w|;n!qqstH-)-d!c)*>Vyp z9qEFfa8k=;E1b!fU=5bpRgDIlTZ?^R;vF|U+-<95yN9dI<8y;7upA<#R2E@-gy*b_ z(O-K4gahmYy#mgtR!BDqjGLCE$b1RBa34<{s(gp2#6q*X!R&l8a?C9TIRsSY0c8L2 z$8Lm*EZBvHCL*EaY?l4T3&VZz>0lvT3``HW3M=ZyMJ zLJjS-Bm23l0$;*E>#obi!8maMTvX9#| zYKpvK?Q_oKkvA@KeOx`gZ7pLF9`(K}sKY14?=y549c}YF?CH-xI9_w$A4W#AD0m|} zt+!*>`pR~~bb`b@FFCWhX-(MRkxaiVvIV49kIXLQ_4yO85$FjujTuVl5& zBB&!?7YY16<(bT>lwm2-Q!9%|X;ssq*?8NgLL}2KVbAl!wxU#UERQoZMZS%gnW;Q3 zSEAi}31UB;GCaiVGG?CaI%MyF!!YkxViC#S_nPG1?cAp1FCXxs3FB6oDr|-AOl{A! z`xQIjgqQ@)etrm)sj1QnN3)q$oE>OcDWL*g245lvt|T`aKc_Tz$1o{wN^R6%MI-oq zm20~S0*2KO7^Qm1odZt`v==<-*^Ej_+v^!w+8@oH68LOB9ooZrtZ~EBti+G} z*b_DFOzg02!c|TBkV1YP3J;9e3&l!v3R;3nIplNDoaXHx((S5jF(Db!>u>0 zqi2PFS1#q83|~#49KD@PY&%LbiH|?!oQq#CrKfInFIKfK3f-Y1n%!mTRL`UaoS;bwFdoMlQzGwrtB|(#<>00DmIH1iOuTa-?0Q;OLbl!=&})3dAVB} zG*!dxM_R}wy!ez(4^?mdh);J_3>7Rh&q&6f0Vb@TI{0nI`q!VBwcYPxM#W33Kwn_i zq6k3XnWmApi$Cueq-i{>!4gTKH~?;7B^VS|+(5`!VBF_-6=~|hiFZpcKwM%Jf3$$l zo&vYk1M$8|MJlw@aWGK!N8;GOW?AYg=!rxB3~)8OgcKtwH}$lqJ%t6XW-|^@8WSF~ z>)Yoz2IZQ}QT#(V2L7XCU9kY@5fH=R#HZq$z}TJd7AAb4?fu6m;RX8(55fDI6Gs@BuV{Zna-wmlR_j zc8`xivG@vTVE=^q`7mxH6XlT|i+G<*i11s8Q_q0XT?$$~I%UbCn~;D6=GzpB{xUTo zb@G(Dwv#Ejn)6`)`+`mUyWYXDu#TEF!CZvUw#;uR_HVJSY6Ej1*MJ;gDq~w~Tl?Uw zN^3IIHxD7P0l_(0BJDok&GjT~L4ry;m}jnAmg@!JK=8)Kb2|O9i+Qvx2E4K0i+58j zuq(gD31R>3!RY=r7Pt((Aw-7=j+jl_tyAifNzgHAyRTjnwzelS?}t^YX`&_dz8wSq zD|r|UGCpVk&82s$ZT1qKk(<{?kM_&L8o0TcEq0k_M$q^F{rl?U_6-a#VLqdyW-cey z`<^$f@&4I`sI{5uq1hUFL%xf?Vl;)aj{L;G~*8#$+c^!&fXMC4Y zXLxtjpF9m6t8$$3mwiZnrA9@MLs?$5={mI!_K*8J{bA+NTlP|{thQroSME80aogu_ z5MNd@twWEv-Z0+Du(_CpQ;D}BWgnIXEyD30(DY7M39!p0=L&;LsR9mU2gp?+Msb|k zv<3{##LDK)rv?of@Vlj(~j z{$5y*j={mztyALN<-pqS2)5YJ7Daz;qcf%f?w7!A^v}R^K1Y@9ymRJoqcSeP)9-%U zo$~K`8Z_rqA#b)QxJ(nTvQN3K@kV3%yxooLIhNI&c`2BcKEG+bd%yoRysDR|7+m9y zT2h?H9?zv#kRSeY<>)5~>YIs37G;kdn$~i0`}(7rbRDZr(ki|34%H$;FAhGoni~XE z6Ro+e9QK#n^-=YK%w-U|VMiVJ0=k7%#T{a{(w{ox5~*w)+s3gX^K%qB>`8NEW!IsO z21{3NfJU^QvoT80o^!BOCott1u>kOl+Bk$oWe0Tu4R9zlbh9Yb%l(ueePB6;rc&wB zE}&VapCq+`o3k1h{wr~hS)IrKAnz-qtID=?i92x;h`Y;)oVXEpcM>4(?(PtGcXuW3 zE`+$dLK5Qc$veocOI3H@uG{_kj;{B9z{pvgvB{o$uDRA;pGA68i`?Z>lRMZb(4I7wzM2*gVB6vy?9|VxwW@ zs&h|f4iCd_iO373lg(=NqhKnx)II=Z+$c}EFK0UF8etP$wY2vYC+H^dVsLDLwR;=e zw8^KRmUa?tNBm(JBI-#kTu6=5$jY5wbUb%XYa+Qnf%jG1ac=-gN;K?|c8Zl`IND$ut+ zd>QNfMlw_&vl6=x9Z7d}Uq*vglc>g)YQCad1dr_8N+4QQ@YZZ?lvr1iOxuISny}yd zop&%#%XPQx@Op7OncJGt`rxj!jUJUxlL1e9Tv3if;(~o%aSyq=f`hf-j#Rs7;L+Iu zt!kq-7-ss+NvW4+FkcEiv6=Vsibr1d_1I)cRQ2<-KQ^W(ABq9z17%i|zC_CC z$OCLQ&X22W`3qyFth}Jeb|T>=S{~8RXku+g&q*+nRbLk)Ka|Bzb)H%mu%2E%$0ydi zo`NvV&w2e)KJ)8LYKOfiWW#(5v|=~g*jtx784oeRb_S4sxvrR%=RNDwNsmMkalsX5mPo#R3r9be~k9CSQk zlm04vmxvA}w3-aKx~0fcG)PVA5@jZAEW9UJTk$+xe9-(@%Xer0xh+2A#sX%{VZDmB z6^YEnVq!t8J+3RJKGd>5Gu36!k7bVM6;EP|FMDm@TQlRdkCGkOVaO}1Q{Ktk@DAWe zhdZI#0b>$2GEJ`?^k3asK@^p;mYpA&tMg|(b;7FI9i0q>6V2Q8)ja_pOOK#8N`l=b zXf6ZN_)d0szeN?sVty$A9~pqa=%U^tI9?!Hx4tYMF{D?3YU*1scm@fuNP>Vki|QQb z-p8fi!anGjzr1R7u~^?yiV!5 zq@yew(U#Er4|*K4P5iR*(lxIz6BMZ+V&I~DJW8dKDYEH#usa9=&$+I~ty=onyvAV5 zSdKGq)sn(arr}IKyYr*DSm||&J#rmXf{hBitMu*g;}mh|$L?I-7<+A~$_qSKWbsOBQ5QYjX;m}{KBfO# z4@C0MT!3r;twBPtY7Fl8g~>wohM0l4HmPvo-ccRaeex7eJV@qP#@zkV@^@9}qhRgI zgmYp+>#ifzH%JVKr}&DLJAy8{cF~pw=q<)PY6FofS@jJdh}=aF=p+b&$VI+G>vOa}4VIhz`_nXsaNIT*n3}i8UE!P%mV8S=jqtpjALd=~DpyWx4 zT13Oatw#4%%u*hBF(>ZLd|8Sh;-84@Ol1MW$9YZ^>_kEMc!!h3cYHivDlR2xda`=*y3JufdOPn$BZK(%BBg^4t{r32x z6P68?PnGx;eLXvHOV|;Fk4u2?acHJx32Dux)xj=P7}{3x^u9GiJf?Q56u2kL3SQ$XSn8#2@$o-+vzJ;%{N{C3 z1NED)RS-TnfKYtbRDEm1w~1)EycqVoLjh+~XKd^=} zP@J8|ubQ;>n#;`AtJ<<8oDeG1&eL(=TrwJWjg(H7d`HLUp&{pz>HuR2_0}H@ENT`u zNxOY)=2b@2G?d%S_CqbOw!0zl6G)!B>NDrvpVS_yYKA#qK^l;(2TML(Tj%iVwghc0sBlbNKnMt#G^ z;o<5DsluMMK(l)5zgte{j2NaS;rDc{|%J%X8sKQ{e)==lGAhjQS5;!qC!DP0EsbSP*0?oj?egNpwX z3S4GJ06jAcfEk2}0|CtRY(HJ1L9$f1bGcs~8GXgXR{&={OI=&~U*Yxd;QQYpb{2Z4 zA4s~Mv4!E^p?4BneO-GSkTU%bH}(tFme~3B%(~%eFyCbi`2o3Jd z9(e&u4UTD>oBho-Z>}gUU3$Je6w|Sgyl((hSB!fQ$4?V$jB1C=^ zzH(Lm*wTK8v}Qn!qR~#Xi%oasu6w>2TEi)51mKWay&+*Y@NR?Pl^%OxUfnII8hsMt zf3=EV+1`TOv2eOidi-=4goOfkvTUZOy#tuknfkH?)OT{)hGcDT- zs6D5wOy$d2I(Fy2L|qYKaNUd2h`ZcBqj=w*0HX)*bX4b32EvwwW?1be;Gki=abI%u z3rV+jbG^?MLt%w+n}>u)QREif21dVYPvREVgstT}M7s4|!O%@8T$f$BKZ+-KrUZC4 zC1`F}Sdhhb#MXYu%swOcrhJXQFoO7@9|dE;K8`hv6}*{MY!?qgJFH2wF)&js2BQg)SkILgcT=^V(`ADh zNN1tuz&BO`CR07Bo0DuFa;b`|EENrm6(KtwFMxJ)q{b!ayRM%%CVREp;AwGDS9QlvZ#@0cho~aF|Q0N638q;N7@SUwKdAFoODvZicl% z%&n%>-Q4lz^WjH#W%S)jUyy{Hsz}u)QE?`l^eSzAl-cgIXPOB-y|Ij+XlL!F5wjjx zhd>md*fooAicy4&{a83)+?7ceWK7tsDaCGwfqwJqM&Ek$h+!8_)Nf1^WZTO_2(am2 zg}%3?f>DMo{JM=dcuK9eE19oEG4zVOgqs`+FJjkPQHCSm%USG%@hRgX?Qz7r99T)Q z=-5~%HBlJ>0I+?MM`t6Z*frt`R%Fo_fqT0x>!zx2yEs4M&VJ7vTec6v+?)c&w&a{2 z>e&=EbL}N%W$16IAj;r^5v37xNgvN)H<2XL@1VqTJ?Q)iq#+bglTjqtSZLqg(^k@4GkGr3G1;rG>weT=uQuIOy$tBZ7=Gja71P;LJk|23WN6SCW z=6!}xnXT`Z#348uTGtC-;w1AN@BQqQ6WZk_E3$<>!B6HiYSepyPxiNOxu0c;5)}$N zA66Y_CQoBbaR`oHzW&q;gL+tHZN6gB=gYKLrMo}lOC|wK^AfQ?0`EL8D>YTSAZ}OvE`sNT%Su?1?Hf@8mVE=o+38&P*A>j zJCA}UwG;C$q_gZm4jVb?MO6T+-_xm=ys5M~JVf~zKHXiNU?;Q)G_5IQ%biIiYP~)@ zg`#E$adgKOlw+y2?Y{mPIB`7lYVp9R9~1S8YZcEZ?OZ%-Z3L29x_>%d2>2z!O7OCB z5ylRue!FDQNPYbFf?SBAG#5Y!hNRrOIP4cwI$3cZv)ajp+;G5jMDItXZz{T!*VZiQ z-O)%_@x)R~-D|2=Nd?A%E+;NDdsc!b%muvRRn=$JbT-ouENAvUU^;3WMuq# z=B~bU=*;+BLpLV(j6_ZogO93ArRLX`=eaW^>QXxAS~I=&vIeu7SBr1m#0fKzbtGZg zS3|A#32i8G+(UBUJs;u^J+3ac{LQtsLH^M(wock2yVN(qJYT~<;IkYAlIBLIIUWx= zwmsbQJyd6ym)UJNy{aHP-h< zFN6u?*^gXZo8Coy@}U+96$OjHcNP;Qx@HtuU+EA;^m7y!I-^sJsD=&jJQS>3%V~ z?&pFvJ-H=>1p|ZJDlH+1TLvwRN&28QTTQ!+Ga8KYi`*t-+LZ>ir$zWSw0K!lhn`1m z7u&)urwwgA9ZofdjPaqmk4~#@&XSNjC!2doPM;znzG%9vC_d`KY-u_|ed<+)xzy`i z&~LL=U(G`nGYNJ*KknD}M%thKx_dD^!}2ufVYK~ektTdGN8n|BU~isep|?lX!M>wp zExy*%=hH;e^ARJBWtOOR@f0}7h@bEpOl(J?axdFhY^4UmUfH;C*lF!V5PO6z2;)Ro znbn9-+j@`Z;(BSrG`-n7UEJ?}~7q*FC5pnS4 zNwM1E0Q!{~#R{lYZ9a+oI*8A#2j(C2rkvzmD7SY!jx+cYTfdMa+MH7~j9g z9p^5wM%*b5+li25Hrk{#ef?u_YIDQ1xz@W?vburh+q}W4ca7OvhuF`pVbvTAZZP3( zQHv!sMqAybfmX;TM;yLRFv5r1m-VcGf>U}D_xtH??*-!Q%8ten%v%{ov+QU|v`2hX zd2y%9iu<(S$l-v2`V3oK_t?u9GtDB&W9rV~Y|(E3&q$ZM6i7sSf!TN!o$BJvb}A69 z&d77Rjx14pJEfaWIdwMEYX-~`nyaZbPC4=wrF~#DxN+T*;jF6*+xp?(2w%&eKLl9# zq2H}L)}GovdHL_2M=_m0qBB-;Ecy5NA2K53+75 zhM0c~Fx`UQ;67i5LT6@QOEZeGd#I_r@2q3eRHFm!6DawuR_! zlfB_2P8oL9SgKZFqahruJu$<#dj%}KvfVd2#z}Ydi#G&CyiX-8^E2+xvI>Hn4?H%j z0-mDsW@NqueZe%kv|LuW%o>sM@)JDM2^6LLnPfLS!=_|QTE5y`hotebSL`owdE#jN zWXHtW%2mo9rW8+u*#$8JJJQ%&Y3My`6PobRZPTK<5ZGDChhdnyXB09KsI*+uWd)o{UxY|tNH6wVUKE1t}S~r;RbvX8|?E2}vbdrN}9sU)a)Qw=4 zUBqQ*2;BT@V2dNxz@^Q^HADtsgKai#rl z(-lf(Wo$m!-Lnq44%L+8&Yg1U&`s4cdzVU$7xf<2muW*$Xl;8q9@lA}kKfmR#;)O% zkMIbBl}5LJ%yTk7)an)B5Gy)FB+2nK!4brU1I&fF(~K2*~# zh56}^PF+h+ylcPGqY?08l4zW$I+&0>96kLc`Vma!;BzoHI3>Yu=K7H|?kI%)1JB*V z?Lg{d;alDorSsMki2Y5O%aK!)U@*$UJZHHukNBF$5D@1 z5@$>1=S5op&-w%hI?o#oD^mUl2C5>_L{vvH>MiWF1sJL7nHT3X+O=vYVP9Q;hXJ;J z|4)1K8q+}h-JgCWbTT&C}o1QbZjtq zh){fIYvf-^Vu?L6iCDNpn8ys>`Y-`IBhg8QqdpVb!HA8`03}M>Nn)A!6A5XyXFgUt zGkpaIgW?Y4HH2&y!AF0=pkS2?yDl(A7A>R1oJuC}9VY01qzIUO!tEEv0*);O%ZNs( zOSzQ<4TU!>FsDO!)=F{^&y;5N4I|Kz$r*s+r)P|VGViB_hNT2P;pVmTR>&T^lFIHQ z7JJ?q{Fb{CPO+Cv`lF-n#bCmrFXX5KxJPG}xF1om*k(ik|KRGtDz+6QWO;t(9`RW4 zYX2fENJ4i7Um_q3EqsjEDM|eb@QLV)+{wGU-fi-gPvkBWglb_C-vEM728x7CIA$op z&KMGAKtMh`f3+xy=m)AE6Ch$`rqGd@JilI>9vDCkjaW*vn_W2sdZrdL8H5m6WP>zx z;xrC;Moe%@njgmAwERE_DovL{$k)9A$%wV%J$l5~SWHjN2#N-TlDd5^w{QB*NX7TS zRbQ0(M}Sx6lDhSnLQ;Y>bS`6WFcHZH>aHSnPSxSAK0)=vOZ$O~Q%&=CqCiE(m|}ww z4<$ZH9fgqcX`Zyf70|W`Ch6C+u=XPg!*$Of3(N6pnPCSvR<-@+Z5l-K>dO;3!XT1d zuxr&EJyTq9-e>60&DrzYFp`y#R46^DCF!PpK4d?@0j3||0Qjh$9+oSrJIoM5>kH*g z0wd1B=FO5K`PChs8z%V1+*gKqJ}j)WIWl4aae2}*7nSS5{l+E{cq@6(*JtJ?*y{rY z8?@-rg5pjeyEoNHOz8trq!HrP)1b19JHC>-Whms6Zg2)v#-NVJ#ORR76Mn}ANaqtf zsK$!)erV^QedOPM5!4PE+{=X*(hkzdp>`(jRRl-i(js~jOv`~;T4;>r&K)9fA;TZu z=?GIO{Sz8E14-vz5??WSxT6iYN6vr~MljcXLZ7od*L*VG9KDfM)DZfccFw~-kCVY< zU>RY=zvxznc(2XtRt*nZu4`-y?G94^D@Z%1k~F`&>fXe3Q7mv*F!Wt<9xqWIzx0FVLsny&PwvNS?g-np-qYG?KC(7<8M>t;lFAw;bkjhV`!2JDUAqCeRw zLF*)88~7|?MILZLzn~4+OP;$dQTDWwrC9%nm{NxHA+$LbuQe2}iKCE2)0w9G*de>F zg1=@%dl^1j_x#;ZbKPMgr`n4q6bK6pYPV|&wc=~y4F%R1Mqqx?C3hQQt@E0te zJ_AR`{zD%~;^qvaq`oG9UZ)poKCbjjZ7H^3I5o9x!6Qhlu6=QNRo-R5aDT^8(|qyv z-$4XG`Y%Sp-<^*Bw@ppizV{wwP|&xvw6_7Z#w7f%hhzB7)RgU~PLA!TPLA!nP7ZY7 z`W;F5cJTT`KgaeHIRNQ=zU%4OfA%&7`HO-+|BoOD-+#5=MdSN#&7f$nW9Mw8Psku; zY+(wzGhI7E&2MMLEF2t69H1ViAQMmEPZLyjP!mOvoDFmn!0)H(|I51p{(>|p8Jp{y zS?Zep>||=DZ}YQvDKp0(4xaxB4cqUc1O&C<{L#CVotYjKI#!UcEs&M<=jeasME$>_ zVf*g^4u3vM|Afr#*ItRB_J2S9U_o+4RwmHtJ;+ZN^o1V@_SXo~FLFT9pJuvpHu?_w z7Iso^?eyjCEp6=0|K_Fphur!_`u3lS1Amiyva);wu)ezx|6T6M$^??Qejof71nqBf zPv9SJ=idOX|8YU#_)Y4_0sysN{b8BQ!~vjZ0|G%16e06BaOy8?nftSx066|2iTz&Z z|76kqB}R-Od=9i$fIO&~KutwC*fzP6F z@gJjq=`{K`A^HU|{`19^i4jzoepaL3I?{sV`~SLP^ta;rhr+@B%ii@L0N_B7O#XK= zX)X0|+`dSU!`EXY&`QI%Phi2vHPGIa*F;Ho#3Ay1VtM!M*$~v8`)peqYUE5jkMdB` z7o%QcN&^q&Sk&jwRq>Te!-F2&GIu-&cF1yZeYw(j@gJP!B+qPWupsF@x4p^qa&0qw z?9~%D+8(U0_EW!`XS-f~#aofr7`CwfZit=VQ=d@E*Lv%8wI9!Szmsgaj3=$Oc)awk zYh{^Ie_zvbrFqH(K;D^tCSrVl1T258fV>dTyIm?d&)s}~d%Sdr{JJf>)dU17i&7?R zH-FK7Ygk<;c|w&?kJ!MwbhYZ0g0E5WLC>d7QKGF(V-|Tie&?NMQf#E z65xIjJos6=ZCelDSA8HgAEF&(kXy9OxauH39V^1gA>u2JRN4&Y(pmPzgM5*JY8N3z zKKgbkcHPh6K?bH>)NvTgYM*ly=cPvM>CRDn*W>$*p>?^Pl`p|e_ol>LBspX0lPp!6 zLAIl!(O93u9$g}8XN@C$HHdc#7DZBz>~v4u`rdURpS@eGTQ`^uhrz<+I*Y+`u9FTA z%SugMMdrIdK=!;dvGMU(U|*~izcz0=UXX2=xKLD`bF#tp%J{PWQrC(M(WwOwS_Zk! zDV9c7>zMlTYhL~tomone)C^?YqK+bBZ&3Tg-D&*F{T)f5HQe3ny^hl~kuMP9;XVb3 zZ!+2_I`OHsche3OEAIyDxndieXfEq-eImuj#Lyj7zs~b|l#P8g&yhrQ%dPR|#7889 z@(vx=NF7j}Pw98}+a_5z>^w!|b~g4)C0+;v7pZL%&B#-LU9OsV&baW}6zgr3FoPpR zWegSp4Ldu|HXIkz8=cwl2qT4kMphlV>-3Z62T#dxiPA9Jp?EF1?6R5g^c83)`;jvaa^9$UDzu8*`#{(QvtL3%C?4AIW3~ zzmn)mHLetEycfgp2>_PO@M6ND`U_>NV`AoOmrZ253{5KJu?wRT6X4M?|8OL^TudgR z8#y}zkXnJQJ2!zw0va7Z+d++fJq*Iy6z5oKJ>oVpYbJ(8x%vZJ`^03jcRCyeS=BU! zpM6G*I0Ab=(X8`E02gB`#OW%8eOI>F1c%OvC#i(2AZROYz6ZIY|}+C&Kq@iyB^U+ z))m(XQp0rv2D;tTTEc@3#DN8Kx9m*D>smw0hA%sA3B#5RJDa%pgSu=9J-0n7__jS5 zv5|2}zGkpzu6m=0VzI2XTq<^sk=4*2QoMUSHagkdAvW!#fqZnA>HqR#d!bX!Y1xZl zAOnMA-7T{Y!t;w)`cPD87SYX}7lE!MNxm1~D#t3a8~jub_BCpf7*Uc7(J&Wci+Oh! znxZ(4myQfi5B46C)zd48bnpi+qKKz9ur9B}wvV>(cf z$6Ku0SMpEF(T*-FYhN76rt__ggoXIL3T}YC`u2Z6`bAzTwTo_TutG%{)ug9}&v<`v z?8qGmXqF)@400e5!bnA4-*zK!c7@1c$AzhQHw@$II}GD{*beY{>Vppd0Ap>(ujn$$ z#Ycv1y_ZrVemk&+@Ajg>Kr~R#Db}fN1SYaNhK!jxv!v}bV6HqBqF2|(0x8X28?h|o6FVL@scu)9 z88N2GeMT?T`PSo3uEv0?n;#@S!ZDnEOX=T&dqVI?-#=#`Q9*m25v)ye(62-#NNJSM zo|(#*28ZN!w#B{Caw%plW}>xx8|Fut_^>^g&k_CJaL~n@#ZVzi%fWq6gknLZ?zyU& za}`(R;Lwn`Bs1@d*5OLtyEp1nac!o3*qjCn$9^9XwG5YUDxqGdMc%m1hAKx0Y1uV9 zo}Baxmz@<&Z1*vMvyc4Eag1luAJsG~cC=r0Na9Qms4pv1 zXr@+OEIfV9Qo|H>b&8};OTu(cN{kMW=`Q&EMZuh zrP!_UFRZ-mjm|?$OJ}&^$EDJmZUHpz^)_@XE9CK}BU;htEz7OX?k{SZnxxA& zk)$i#NbfD*c6HMPS^0aLt;{&@hh1e^aI1e=Y%qIZq4$NSqZH1-G@qj|2W8$b2{^wQzz2L6J{8#dLyZh&hr|c9pr5KqQG?g=B=6 zXFrXdtW;t;t{G?2V0EN|lWpgWHi>4!Nu8Rj1MOAv_4!hubMN-SmqZ6!=ppaw#Of6$ zM^WBsJ?;CHp(R7<0lsskkuL}0fkxCq^I`05O?raDP1CZJ30&(&2k((j1%tX2BKcSx z_mGpCHX3A^h@>tK3NSymz|T_=2R#dCPrCd2I-!X#$kg>UR^29Sxp@(d`{Hf-RJq0- zv-(9hk{ZyY|AWRwPU|h5tHxlbmnq3{VGAI~w^>qj()p4{_=U8fAnPb|rt=v6_U02{ zq7s`DBP}&AIEk^2GD|y2VVF4*iJAEBrUM~XtR*#@8pM$w9#{%-);VrGJ2Dt<6*?h% zW+<11OAb>u^VV}q9vBxvkz$2qEYnC4%VF0!o1ur#I&?v*bnsPcBejiH0_5rz1(zo3 zaBeOs!t|_d^66x08N+s0&qJ)o7u2cKQ4R7{?dOS)yFR~KGY4AsTFfZgJXB(O94{~9 zeIjx=s;@cWt83z6c;8Fk99o{QdfmAPN%If{CP2} zh&~5Zr1aEnu@zCjkB)5|nmzg{&&wKeeX1`Z6~`nuvg}j^pBEz2#HT8}>%vm=((Dpa z@^l^Jz(21+0EdGvQ7Xog`1!^$yIuK)(YZN8Hv_z;bDIZir1fsH%Om8aPM~7lhW&Id z=O=S$(V6S~9Fsqxq4$t-;ec@nM!|okaH$2Co!+7Hos7nG3Ny~j(jr2EqT$Cbebbq2 zK-^N+)sLG1b^-ONUEyUZl_$_h6u>ZmS%QQ6<_*LXU$`gm27Hv>@6=+CS_SF&^|l`e z`!2*QMv5QP5%+J|^5oqw=6fiz73V!p-RC)5%EuVn?qBw?G2#F}2k=hB&K<`_Y!P!f zy@E&Q(D53vB4+Fwi)k$8qC;6%xgon{O^`(hx1VtiwVg{nAOPpbdiennE2M5Suhe4h zP_)u8zn=+r-E3=8SlWSYNjCg+Y|m#rMuSJ>y7U|<3bUx6@Cb3BUS3S{0;5GBAJmC- z+xY89``jj;x-Re|i3Q0{QlU})`|Z{61^lb+5$9gl!^riB$;M_!P7J~c0(bvdj=ip& zV}=^0OUOF#B%tlhbWM7NqB*oZ!p_nKQpQ!rZ5uTep{&r249aMd;>`#$F{a!HtHFlfUIoB~ zOH!+|jt(~DJ?(!5lke^YwgGJC@B4Z~=&y!dhPb*6w+P|&6e5=>*&dG18u`hB>-C~L z8m-ZE@#aBvlGLZgm?j#Jc#b3b^PESa1QAwfeZzalwB|O|IhmV7Zs$j}v9hP{eI7_c zZur)usUo#!wDq2z5!`~`$m;S7NjVtNxry+6hIh~vM3H)8T><7NS{}I=G1{1NDg8F` z6Qi%H*qVInh$-|)e5b5N^#Zp8y%5JIe^nVKZCtE)2iF6HU^C6)4Hjulr9pS3p&6ys ziO%=Y^J97dp+loD@bzOk%ney_QR96Dua#zu+U@b3S=U7v^7OLAB9#iEcvdYlCWtv! zzx_d}@g~mlZ8MI=y|GO@UUto4Ck5@Q^66u`vLo4cNpic(E9KHy%6Z(F&TEu)Ia2I{c<1n z@k#hH=+(v^Z^xbp^lG!Uwd*C~dcxX@?z=ARzU+W_?(cu0h5htxt$E~Xv)ZuL5?Z)` zu|ZfF2mHCyWxj`$g%ryn!%Cpf4DzDd;(Q8Y*ayeJ@jB-ovzcH$i{?Y`v4_ae*B%Ea zR0~E4)*-_br(jH>x4R&t>?Shq6{NR|4v@U3TxcJug7`)}cpXo7SHC8PZz=SqT~!Q( zEniJs952$q2&^n<${c8O*fqLCUVf!$=UePti}lD&9&XjDQtkkbbK+CL*hUE#x$28Fi zFWWM@HHdBf;aW(@FPu(EH{)+jW~!l{8+B9*V-iBC83t?aTOD>gzZ883Ll!YqYZ+2-c;31%i(a|MCP_^)ei|L`XUO&tW|EGj2#ItIeo$|>f!7It^|ge>$I5rgtr<946Yxc2az-d3(T8_o<>jH z9?SH_AZokrJVO&oc@|$mS+cW%#Zs!6=$W7Kko0M~F44jLDXUw8YMS$2`KXKch+r$F zXcI5dX%y~0*YqvuZ;euS@qi0y)fsl`SJp}s!Qpy|ZUIa4!kWpH+1E~9uhpL1xdpn~ z_+q>o4uA0#>){0F;zN^5!*cBxQeyv%rO5Sgc9U!IDEp^dP0!b7`CISUYWl7cNID}A z$ww>~hB%{$n+hMQVu{JGqT9|X$}<#1w1Q?GWr8PKppK=vJ7 zkynpi4vMBg{l?0{(cSy3r|d(eV#jtFjBT?)u2mN#fVZad#m&_`Qp>q-h~3(XnX=D3 zchsZ{kSt(*SVV0g zOa7{rd4Zwd&h%EL3is706G-|RF|TgGuE+Iit^9-WLvum&vsY9nlIoQhT2WjRs5lsz zr%f6{5!a7urc+P2M|Qu!!=M*pm%InWIF4PFP}-AIY9jg>!g^2K1_dLLhzqJnYQ!8W%`v$1%A&oIgrg58 zp+PHTEf(6mdnU{Y%>b=RBSYP>t54lTxi4&^XHj<4fZG~OiX$w4S8%L~yBoSzrNSZf zkg$TiwB9s#G}o>YTx&!Y+!R+l7n78L#0O&j#KaZNb*E_fXYt^0Bui5PKNQxOP)2fV z`X$YltAV7!RB&ixM?*%$(g-+7_N>o`Kfh#4%u%+-Gh+%=(p1e}yG?p01Xm%$Y`hd2 zKwh(?cSWToMIPjdy0N+?$ec*&t7bJ)Ci@9GSr08RC1{r@XR;`l^hG+ODk+HhBQkbG zhbs|vcudlB@Bz)RIydTi&mN96cNSc{RGd(}!5`HmhYQ_=BIHSQGv-WI?t%nMb~ma4 z(hOV^e=vgBcY&F(v2R1J$O|n7^#KbTB@YS$n-ePPg8XmVZ8>Y8tECaM!V5D$S_6e zq#Nv>2)U$SK{8Rq#BwKwgQ9)U=x)XID5TmE+^=txfVc84;QGwn$fWeC$gbh@1YC(u zMQHNAXX>`%etK#q4Ie*D>Zx5hpz_v?2aulDMN(5g&qNfbx*(U34j{ek4#2_tbQEEv zT-EzEr$6yln=E_%lW4ONohpN}$$IW);3O$S=oHadkP>w@jrundkg;(*?qk8!*VFOXJz9@@;7pc;nvSEU&?kwf+IP>C^%r}r2TB_*@irA8 z_0g~B8#x@d$YfOxg;R3Aw3?7id7@rcaxj{Nx~5AW`NsKU1aqJ9_whNBXjgZ`1%3Eb z>6fGdsH%8PEhBz5MkX}Gsy^Ch5=Hn{(@VEXWm`TC%XaMitQR5~tWApE z%@rT4(3s9*9?K`Ugp8(ub!!k4hoiczl_-^qq@X_UP(`g^ z7Cq_*uOaxvz3O%Azpf^DyD9%o&=;4mX_OZj;rg~bi2*&X~t=V5meMgr_!)?k$mVo zD!0k4a=O`Y^t?ZCWlAz#G1Z_eI54o-R-#BW=~G=A!mGQxKoj+ zBkkV%Rae%p_fE@8BO@EVYT~z;LRsg8UGCdnJGYG>X z1cH!VCg2a20~;$nhBnL=PeefI2Y$FUBf=p&9*+5b}fn!SP2F_n%S@Vf{;o<`3ZZKS7K6H7r079fI)(>34*Y}i{d=YSvt{O&x%BtwFoVc>KmZ#f$YKEa z*N)B~^5&nQ)BHM}Kz;8)3>pv_g79~dVgEV$*O*R!$eZ6s=KE^;XLIJ4rRlfq_}z>G zfcQuM+h^2oeGHfw|Io&OiSZYwe%3!MRNuE7e>PCROs>BN3e>~_WWd3}4&obu=Ggxu zf%-!>{ld`s&j?4q&NF5JJ?qbT_DhhM7=MobFP>+ADx3Zgq<^!={*QNqfWK2-K~5xp z+YJ83%KFBG{g>?p|HjJt1LYOet>h1{4FBMEerfOVt=S1X$a;kh#OGwCX9ohAm_ZFb zKwL%O_tAgVGv@&4832L0EN?mV4D>)-OI8B|4kl(@9eo|{l%^4 zM?n=d($_V$vNX1^v;DEPWo81>Nr5Pse|Xye#0D4eYk0o7^{|3yoWBbXh^P2t^#7Ug z{1Y2pW*|F=AP;(B1ArRA{FXf|-+ID;y5_Ke7}I~@>;YL%(Mf^!tbfR!e`3S?yYT#$ zJ->$MFPuI9L3sWN2QUC5UkKr1mj3kQgBPsj}FGQ{{7tv#R;3d$bf z9|*JGk2wD1p5=Gp`Q{1sqxSq79@d|uf4$oC?}q2c$Jddi^*m`!56z0Gevw)9RPNeb2k^qyJw-?w1YnKccWRF#~?3u3k|wsJ(;ELri3&+7*8B=SkLCMjX34O#9ZHn?`-GlerKpu)pFyJe z`<2JW+o=wEgU6Z2x%-=qVFyT7+Dr`1uge-uId4p)Zo|_Z+irFkRvwPx`S#4!&>jXs zLk^F}p@4%oQc_1aYgmK52}h7^qLiuydUv-SahBN6uCBK(XloG|?r^8m>r)JFjz7#OyhDkNrlEGMfOVz&1%6#B)*+Y%XInT5Ia~X z?c^5b&iC3f_^7`g*0ZnAkGbX07q{=-^9 ziaX>oY$)a@1udj$flMJqgp*$TI4g462DNzj%I-SPhkHwpQ|rTVG)}gwE*R5R@0Feg zT8}s9rS8{q<(_)l(|k92GrUy?!ct$Lvj+!e^_~&9KYiO}wwFIOmtfe&xtTvjlw9>N zW}OOsZj7hes*5ewP@_V%%p9WIkgp85tmee!t#=K$I$7JT==FTSS4iBN3b%1Ps!G`4 z#6-Td!%pL4fBb@PNq2?>%^T1(yFvf90dN(iqFhAs;ijnORH733{Pc9Vv3@e5=-d^C zn)D_nYsGWfSruzTvKGy4-q|t^Lja<%ucc0M2yrMQlp)g|jI<`_-kM^Kh}PkPZq<6g zJ1rhtP+MwO7|{|u+ysd30q&&Md|4@0VebJ(BiZgP1Ku}Vu>qE*$U$|KP{$7xw@V%F zTOx3Llzxywn#v$6UV>M;+GR=t3)HK&%WMBYMp_N?q}%hhtxe9epS0lyD#VulIWF;5 zoKa@ids(;n`==i5NeOE3S!Yyw(W5~=tTp;mJqq1ZuP!$nS01l#CCd<=dN4Q96gIFC zv9OWm7~C&KmbMr^rP~W$dp$UE0lX>^tY2NlVZOeyZgPgNGL5D7vS%CJ%|}}i zc5LDP@xX)Fre%sqd9hhs^UtZ@d(TLAW)r~ieFbAl5a^w!gpD1aiQo3H;{^9j(~8OhD+js2Em=8 z`GBZ&im5s%{J|@H)!bj$ik#kSX_|12!pkrwdOOH38xMTIQm)C#5zbz6f1G5k9l{v& zRPDj&#?2PH6NakYY~9dZlui?^D#i+F;kGfA7@mznq@&vDD2)Pmw>8_h++<$x8ZZE4 zB((A`fyn$>&!xR1&BZaNKDjzS(SZ*FQ)Pv>(Z%w1a=NWm1qAfg6W8-7SP2_7AIt4! zwQ<1Ok*n3M(=nBuknda5r(~2oQv~t$H*@VKpqC{A%v*;B$l+in;t-qw&`x5V?q$K@ zh)}2K3>g_#`Qm9-t080~tx&kwk)em(+ixS$aK3Wzg7JL3hGoCGGs1KqDndtQ7DHk` zhFitPwIJtI`}CQ#LuVZ#F=tF!!jkz6e8A}XL7~uyhU1QaJT{1grB^lQr1dIwWED~9 zh<}l*_i)j7!*O-~D#3Pi;co6$FaB6 z_%?O!3N{`pT?f2yw3dCFkkw|&{&b9$#e<*ht1x##|A$U2DE3w6B);p@AROpBuw?3< zsAN*})5!6!kui3W?MM|J6fGy|R6cTVX~|7?&Q@dl?C5LoQy$0lof!*#;CC>r$Wq~X zbA;bu_>lGH=O}&>6{pZpo27HXQex=s$n(!c&-Q}{!?YsHgy%Kn14u|{pWqYT)V96|ZQ5)BOz75W*9so^%h zU_j+N3A7*Z?A)4=J`|{mN-%KI%RFCEZcEY`U>s#Kr~3Pazw|W( zLi5prJzEu<^>LJkINuDNh5x`ex&rhf^}b=7q|2WN4@0*`mQPt;nGhzjIR<}y4k5f zx4R%!EySFp!Tpi3NAJ-Cs4=c4(a}iKqLW=JC!mFQK7n{T$$QxL<;sCIhg~B4Ebax< z%Yw8sFz*X@e?o5__&3O@5K{Jq4WbYo27X^{snDKsqf?E1a4o zYxVigKE@p5>2IH5ZGfV4bNqt3UoaT&AV6ro3Z{oOrq<($M)Jw_bQ3=-fS}g};-;n; zB^B{Y76^Pk$GGGgHr^$7r!zGLB*8`I07Q7%glEEo#4@i|lSyY{^8TtlA+;F@;PUv3 z##+Q>cCb&XVLQ3$wdC6kPTpdFi58~7h2k$6o6%3}w}DWHE^c^cXh&WxXJUO5rE6n+{%BIEfwC)2&y z(_We0R#rZ=;72BevZScSloznvB-NO-=dpv*XN$2mA?!?_P#^iFJd38~lP!)IWAjeo zC^lHCZ(5Evd|GgqHmUk@e8*iHEih$<^+M_gLNrHEp&-7wPZk1`UiHOy2Sec2;J?pU z4<)Eo};4nhZ1;#Btpi>qc|mqbxNQ%B zj>IDj?Muxk%@)cd(}}1Fj7^n}N|2bPYNcDE9+!FTcTFlQx*>}yEBV&4k4ij{+`fsj zkjiN;S6@KdKE(()clCaoyL#jG*(DwM335^iJ^G-Ze`Vp#_=0BdeDCbZ7`&*w0JZ5SR!m^nIA#q3eq$Pv;C@?=~^$ka3g8Vzru%H>s2vX)53eDrnzP)nC@0 zGYU+a8q3ae6eYI}gFD)SR91v~7=e1B25k!(4fMUpH6ulQXlv1R9IAYA^75qwJ}o^N zSqdrs7dI$?`p_f0u1UZ4E934Ih#fdGBee_4Uq173CVwZks31)axwA@~`zN zp0k?_>>BsA*oVF^YgoC}DV zP)M}n?A-1gK@{Er7V-;*;Q48uaUc!$BTF-;Lw$!EECJSyz%||LJLI4=fz&qU9ArqyuCxNU0R)i+Hqw4T7i3j<3E1ZbilRzB&R8C9R$GVFK| z(=_pb=b`)EkTUChT$ByQ*AEGi_Q=q2tO(%WP!T?TPd>oQ5ElSSA29s62$InN*yv&R z9cBl}&@p(Xmn28uy0X!(fdpg*7-feP2u4d}NC*38aRfQI>^G5#0!0kHJGglUT?~vA z;9)h=*~mhmDN02h%11ITN}{^?7vzE}7JibFiI={wC?{Cq_$+O9P;7Lci-NBbY{Y}3 zS5e-6&Z(l*bgQO)D{rp3!%z~Csn@s=oEjqljTN6f{l?JiXiRF5nghM8E=p;@4^(#{9B#%!hk|VOH711>!nIz~%0E(2epzM%Lt0UC^Gd{`lSJRH=yVE; z9DO6T@XhH2XB)y=)U9%7NZ@0U7azu2R?k=`6dYHoegMV=jmM7oOM9m>>~s@9Cal2+ zj}0BVhXi>FBIObU`~gx0#`XZ|ZS^(IgK#;eUFr;Wrgk9!x6k#xPkf8JWBUQ@u)9O+ z>1HdW_}cX2eSvM#o_mm1gq#l-cOoy0^F&=jZ|keWqi&jlUJN45n$GNlL<1=NXaoW^ zq~uv|SZLRM8X10^H=zMRbs$g%7NN@nWHt1L7FM9whGJY8Jb`|8Qkn+Ag08A`ee5~n ztXZ(oDWz+4b%D2|V8?K@5vIExMcIaZh-5w^J9+EISE!qLQ?6e2&d_9U$1kx4xRhCD zO8iK~KdWXr99=l+Zz)BiCMw11P>>oEe~5c9+-Tcdm0c&lCpK)5eldB zE`XoN={?s9%Ml8#S1KqQ4r9cN-mMow>l+#Ke%k1AWLr@_sn4_#(Pm!lpi|3W?|Ax& zOXXtKm#NZ+U{!wlkf3@AQs2uBZ7R|=O41d*Jfb5@&Lxc+Uq8*YsYi;Xs~Lsz@zPwI z(9^m#0{L+6MJWUFF`y~`c+}s^DduFTdUQ zF}X02u6_|YTpn|}F<3aD?AS(ifJ<3pO{syI_N*bILZZ)K+#uecx(b^uIP^=iks4d{ z6xUf2bv8c9@Kxy=L5+ji!!MzGAz9LP>~5qXKs>lSixt4J9#ouq9*y*LgAwnS@VRxR z9?~58L1pe$=QEp}TKEQoS@EJQF=Qur+7opi<9P&Nz1^9m0n{pCorebObA&ca2zC8q zBB1G`=VjQ@VYt6vvF9@|m4`JOnRKE7tZylZSN zDf~>mfg%v2Q&1mtTq+IUPL(Lf>cAkF1d*l^f!FLSA?-~ZZ7=GRWEd=t$78mOpilBq z^ca#RyeZb(XNgIRGkx>ezIlcLJ28KZrmVZj^EC8~TM4!9ozux%Y9i(_0B;r;62tfn zd<^_5Tc)7knse(Mg#^YSHoM9VBMG{2PLAmu6DWVDU&M-eIIES{!tGlV6!d49P7Gta z`vmwtHehzN%XBcMb8e}b>u)Ms!vsC(wUjO6bS_>&WFg4_czm$8z@x)SY=TQMp6Wa1 zGgsh(0D}ToBry(Ca;>3?L|*2?StK)0b=~e0=t9=xOzsWuN-=qS1K(e@A_$90)#A1} zn62WjU4^dLb&KLt?gpuyC1sAV$jl?o;?Ln^>uiDx(S`;Op(4u0;BX~!SP`odl%1Gb z7pWFw=s4OSeL19M?AtaO5d!88OIS(khA^unMvPuvGnc7`AT(l1yn#6`6 zXh>{J#5rfZGHtLhjU*OlIC9Jy4$rkwCff##nR-q*coB%XP~laB2*e>-__75)jN6<- z%GF_&1qPY2gG5u0e{L?qaROcYZe0V;lwSkXGw%ZY1`DoEe}JSy;RH%BCGs)B{piAtm|ZhacauD zP!?D1;xVJCICB(N=u%)Nvb>b9Nw?LtV%4Q&G>L7Bin61*PTEt|!nK*e%G($k>fe}p z!`<>aJsBztt$$*TV^agS?9AxWvo54FBl9^tI35!H>^97Jl|$;@yj2bD4F?LL*PgV} znH;3>AW0sXW$(CX@p$~y`rI6F`;tDKb=ca34DusS3^fdf7hhg}!zZl|(-P8(krPz% z8E5et;Iv716iK9wEMXPD5s ziFV5S#2XvFRewNNG|`l>@lO2UO>?$1Ng{)gduO*NCC~$M0bWe0>25<#!@qOaS>0d^ zZ={WFlfsK!MdF+V;W-qQ!W{SthnNm)_oo7M#%wz8Z_ zGp7F6t!xKxuk7sb5C+`aqoJc?@UWV9W{QL40%;`*ZO@{Bp7ixct%^r#Qh4==m=&aD z*|z!%v-WYR#1#3SLIny0Nffon4L*muibr`|c4+7M9E40ukp4Qo3V02aw@Em@u1p%j zC!Lhh(T=ZW7#?KBXDMUcS)1I@r0W`dhS!BWWlT^VgeTDHtPrU;thp5Kl_6ILsb7g( z#SgW11DNxyY-H_;y6cjBx0D~Djk$2#&9Ys5x!|`-MQ-dw4o8}sC=%-@JWoAx2-u4B z`p?y%-V?UNY%e?dqt*4%2h|E)V_wEeuPg%1EchSS!}uRhNnnOc8Ae+jO-yg!44zd6 zmcP*b$^q!TM+u?1SShjA?9{VXRvA_7Y7r54vmmGA}*Y zk6qGG`$^FF?w0@lq@MD>;@?0cx_@Lj{%`SbpqbD&4EtZYLoze|z_pnff8g58z@9|k zux)0ban+CCKXC1DAjJ2-nSSEhOh52%W~LwbH#5@@{F|BS=Xgv%$7A|A9@Ee9n0}7O z^m9DspW`wA9FO_?c>f8v$sb?!Pam7Hu>*jetA0@6zZsu>vrz79Gn1PNfm&D>8IZ-5i>Ke zGKifSSO5WF0{}sszj9vuH|&KCje$1V&J4DOc82DrP7H$I|CIgl*EjCw_mkiEmCnBr z9$-U5U|H0+;)P$s!}jyyUnQIWe0Y9AYW`2mIRI#}{5Q+b-_*nM4gBL|X9rd){;!Y^ ziOfG3f&N$=|3L};8l&GN^t%}SFVN6GiP4|o*#C~@GjnkMS0`#__P=GOzu+nR8#lL!dL(sTT!6!rgmQ6Z55>i-`E^C#A_ zzk~+(5&&#>@NLESyU+lA%fDa!3(~@Ov-1CJX#Px5CF3_$0O?;gV84&Q%Lc&2M$gQ` z2>_N5{ZE(8KfFAC-&Oj9*%!FG@%PyLrkmfz=6|+s{xLS+cG~`EY=FJmfv=$EC>Gzzw~{RjpFFHzYN`g}0HHHHq-lf!&O z6TZ_1gbeBS{yjD3;D*d7zFbx$n^sBPtt`8yY6%|0@QgR4zhCb9Py6>pLcSxv`S)aA zceT36I$tf4u#R-k4NppRg%CJz9}7Wet;WYg@vr+cX3QkTyp8EMTQfJ0PxKF;;4LaX z7McV=;pwP=(kr=X6+ZfZb-rHYZY_G`|GFcz%vVf?ovX8i*X&^`8`w|4ps-u5y%t)u z>~Y=C;KmQqd|C`_c-|5Vw`GzTZbrB!XD4Xg+5qxZ)MxiZfLn@Dd{cKNOJ8E&z8sgE z#H?8)->3^OO0#7I6e0{Ayi>v{B1u-WTsCPKp0v3{VP!rHomQ`-o%|X4s@?^DuP!Q8 zuqYlp9gLvH?t{6+^&po$MsZQag`e1#?72_XM;u(iLTlrrE|HxtW4p72ZcSSLSg3Bg z4sb=w{x>!ENBaJE`^{NTb+dM``TYDoOON*{QjK|u*QY0~U_xtL?US%);F~wiLG2Mk zu|9-LCw$5G6^8^M#iL6}t9z*m6?X{9sy^3*_elOrz89bn)*TI!VZB?(Es!Uh zC3+>0snRzv6)&GLIy47lKt{$wMoEvE8|Xz1a)vw_QW%ud-DIm(cJMYJHtDkzx`Kck z){K*n1(}Gh^*_IS+Q2W8k8cn(Ws0i9gsvHfc6D#5cE(@pYqBVZw^SVo!#PT}t)Zv| zAL}jYq$uvyemG&9&V++es)s&{`S|$Ae&X-rU$(S@`S~KWTvkzFC*piTx;;UWg{;*o zG`>qPyx^0(HX9;K!lwe4+2Oub41mxDX+q*Pj51lo$>=b;FYi&((67Kgqw^$dfS zs6+DrM!3ce%!{q3p0--}>=bf57fH|XPOXg24#nb%?#+N)G4qO$-P+e2SH8@Utl4;b z_^i^vrUVXnf}K{&sPf1rb2?s;a;)Acm#&wLr<0Bn{^{CIBYfWB)?uj%g5Htf3%lJ- z+$*=7F&>+Gb#vcLx2c3vh6mtQmnO)Ng8F>flKCtqB-SCN2?NQs4>UVk&5J*s_~mY< zEJKb($I>7nDQakBfY(OMG`$^y%&OrUjIH4^XBwVZKvWC!<9HuuwBe7y^EcCw)kbdX5)F2tB27;2|P ze{`4#bh8Z4CYH=%JDX1f4hP}kL+ZO z&1&?HOB`eHE|ZEW1T0Hq`;~f_+Iur<3>|B9Uy=2W)gT8K_1(uI@9dB-I;ikcxq`M1 ziH5v+bBrng!42_rW>D`T%dhRt?RL0fh#2yc;zN86`ECwqP#%KYs8L8GP1y&TFUM?c zYSQiezHI9IeZ5EWM#G$)I)0{#@YJR^Fb>Ya3gVp3I|$N71eiHDrQ6K zK(a#_j4f%9lmvynjEx}#ot2*2gAhmWtHbzw1yzIMJ}237;l$IM>NszdGTxM4$P76z z%+ba^zJI|+;R1yyLZH|zX!7QJ@N{8V!LLt-qR z8Az}a-+K4h1N|MN|J(-8yY|EACDwK)s(dC`ba0t2-O-A}K@%cVId`&*&eT_-Ve#R* z&zl77S_4jvz;K}O*8{UH+d$M=(UR>RR$~@p)b>?NgKF_j>~C_BZ1RA4{K7@3sfDs&%sOzP!R(*HZ0u|oCZ5y!WVC; zq+d7?(n`2k3eL94<--A&d)M*i@n{=7-$k6al~J$KRVO~u4wqip442&`DITn~BaTg3 zi*r}Fo2e9Gji|)V^79dobZL5(Y!&NJ^{Ymc8J4R+|Dc7A3k!PWy_Vio$jDBLmmJYO z`Y)1_F-EH&#^y<9kbKEQn%bY8&+$%wiK&L2yQi;WbI5ZvXq=t#&d`8Q^~gNll+^9A z&96rig09B~dj)z4GikhznH$QuX=nmy>Q(h1;6cEUn5~Uj4J3e4Gg%%BLG}oY*4zM9 zp8(4prh8`L9*LT4=h#uKop{7LqyCxaGiDguenK4I2a{Y!`)y3~hyVZcL%8M~Q zbcFIKXBLCLPLIumAFK&hOpI?*b45O%>2=l#+v%k8)%H~q$Hvx3aq<9!Bm`DUE3xgH zix@h1CzB)@rr1PAsD0`29(%M(ryauEKF%jVgwRhDXyG_mnXL`?co=H8)O$r@bQI2C zzc$q3td@a|>F_K(ksVz>M63}(P?aK!^e~$}gU$dz0}5BXziXg^TE;e=w*QuXAby{r zA&$+oldRk0IjuqmrczEePKhm|K`uOvoyX1wM@NS7cslY(Q}B-1LRG4rHtzL6Pxi`4 zD$;od6TNePXu|!i@={H8#QoDy(6X@#j)A(Ad|vwWPYB3x|^wI@ZyVUXadi053}M2&Stik;e+=))s?$L(G-U1?K7ao_sRNmf|{_O6`|<@>=m* z;&0;-k@1Nj-Gu4b)*8~s?V7=oW=I_^<-k`SUs)*Lq^o+4hLFt5c%z3(#4Rn>FD4Un zzF~R)wr?7NxEdliG`OJ2O5=Sbq7<92_ne8%5c?dAB=@;(hJ?^tJEouF4I8gLUT9Dr z+WCOR7d*Re7=~sSDeV^Va%$bbOq_gvXXu#J*VNB-^2$*;IvLK3SJ#y=-&=e*)9=V#Ri% z;oTQbU75ZXS4Jr~xx%zMFpd?AJ%YJd{#SHhPdwKIY=(TVYMaGhJJq??W+rp3RO}sZ zdBYfIuDHqHC)mO=AGJ2*YVC+ZB5uaC&c^X~A&YEU$AexYY8}|b-JqO;?8(1U>>?&F z3Km$R$Qu=CU5m759N|8MumP6~nDOF9P>(pqjGk}N=r$-U$qjp%5YtVhBW$#0R3%I& zx9MjtrX2*nQ1oq0lKO2;qEj~)QbWJj*gEwt^{MFPx^o@XVttwqt_ctBNPhTY_vbB?)L@a`z`Zs9tz~s6ikf)nHcTl0^3(h0v_OmDcM@v9)oxi)}?C41b0>* z8F^MTdmrq_lV=*+6k)1n^Gd#0o@8i7$)kw5G~9zRzcE283hrzg#O& zhB(^T#DQT`!BFVn6Q-Wqw`HV!8!5WuW!%Xkik=8uUO7xS7U4M2WmKMoYDH-)nbfdT zj>$crSw0*2VRmr*_ z%IwY;lFUrcLt(KikKdCb&fIq2MJ+9c>(zUDKj=zaYxo>Zp6a^E6Vj-1`P9KuT4bgc z$XeFibukRA=aJXRp?DZg=NmHI1ZPS9!xqYGpcr*Dj+QN`Cw-*ahoKaE3EMQcueb3! zF3gRUKcV&;@>vK9YDc0bZ3F+S4Sb~`h0aZ~bjaIIKGLQj@@e?`P7-tb)AgOuZncp< z7#R2wedC?kBU*FELUDV_Mw*;Lz9SK_0=m94)hl~U$Tikp%vEPvaLKfnVLHhTj&q_> zT^=hLxt6eWS}^zzYD0+7ONMNsj)FCBgd#Bm+hPcy{J8uemguFdi!*vy={teDtPrnHxaS$C{VJh#mBDcM#ZpZ!xXIYh!uGOPpEqH{9oaJgGj&lGnKMUY(J?2-d(RztHE-&nxJ&q|vuDt3I#}dc^sn_Ex??mu?HQf8T z`TJ2$mLf4j^3*=_?x2|fj>hY+VFQCY#q_!;WEi@hJ(gt0N??e!9^FW{_`j&V2tG0Q z%t364y~?E(p{UV35eylMk$l}l{kR6!_=j}+rAf-n2aN5cd<(>)#cHM3>X~YpY^H;WA;)YlX+0InL)(L~ z@DhE{H}SkH(EvS@)Pt9frab{Ca$*|{YrUZng&O5Jy34d`fZFQ%ZKo`w5}bGA2YSz{ zJX472x*rR;ghawdSoJm-U1DKZIZpYc@mK97Llr#~vT|YHN{(-2Dui#oX`iKYfEJUw z9>O#n$V14@Xp4EKSJoYra!}zw*vbjZwgAO2tBKR1v!l&2BU(efqur|Ge?II?L#5F$ zZ{`EXdfAP1^7YFj;fh%UtHppoZ!K@2+%a|2NjcqgtI@HZ0%{eQ;do=q_FdgOm_Sxe zGYQ_fK>mlt*wv?F?KpN$@ZDIhlmyRB&il*#W=SZmnoqGA`svRH!4_USjvmv(evB}4 z7-HVa=pZY4=Kqe}k0>?E^z8lKhrQusxN{=~`>_MfnPYYdh07dBGa6QXTmEHsC=fg<3`9 zaLhA0*kzoBE|4C&#C=CU60$j%mFS;lQ&xvpT28yW46sGz6yikLxVl=l*~KAI0K}o7 zO+m$^uJWv2Ty0(;3lz+=R7ZK_dKp>?zaA%Af@u5gvK>no zpLvL9Bna^;3;ibXV#0KL`Z#uUA-Jf7X}trREh`6SLWZNAmS_*tyG!;6PS|Ua8=SWu zu<&4osVkKJY1aEof&1P?qbetwa`sYRLj2^bDCV35@eS?d#n~9|nor92pBa~Eenuxu zQGgQbk%x|Oq z5#652K)@~J&5z)~ND-LS&;1(JS41eAiD`sa$7F6hV=PU$kt6z{#JSy!aAKWjeAC*l zdU%Q1+Q>+Y<+%bAO?N7-pIYdRSe5)((4xsr9$xJXT_ZOH#~JT!=E7L4oM6-2 zn#`1%u3@OyVn7#B71=iWImgNBy5V$jx6u>Ny7j{yLU554ak1OxTXm;~-U2n+H3V{j z`k`$eg4|w*M&r!4BFr%@4=ZSYaI(>U7efM87VK(+wz&HxK&H-}#JX4?J8jvDn6hdu z!pI@f)@-SXu)>(zr*3=$s{yHg#@zl|Q(JEAw1U=Wmblv=tnZ@a6wg=TB?=?<)W-9m zXZ(l`aG{wBQcFf9TM=Y7rzDyl%{C)i0~6RsHLjOLoO_IUojCdt27)X;$nw^wA{MCt zX;^o&7!p0slp|K0QpsC~NeYgzIx7tOujHWyTOyD3t*@BMx8JR|tnI8v@hVQmv=1aJ z^JHbnp?>pb7@C1 zW!4RZ*1ek2ljKgHoi}@Zi#Vo@B;$PjSP`}^T>0T*dyB?l`#oZnvpoZgsn&hqwj~Ej zSk<(|O^k%C!&X_%h`h&Sfptr z(6A2AoCaBaUadlh7Cd6K-s?4g90F$!_GtIX*_2x|Swd8prq2kXB%$_S!zqxmiWa=k zo(PFTC?=rs>BkLZ(RclXpjVhkiysNsPyCOUp0uSz^`6?!capU_J5C=nH#&EvK{Cq` zd+;8}Ei_Q|Hz5exRAoZqFq^}gv8vq-JBb6K1L%oeYY6P<8e$c2+Uy5Xbl@?;RAbF4 zjal&B&=g;#=EwE>sGXo|tey zi+p1`P<0n-w@nmj{*!dE_)1N${1JoLAme1j2W4+}SKJRodQ(BQXT z;lY9Yl#pqA#}XzVtr|>dPmff_!L2mnf|rFDme@kv2J7SDQwM9m;37qJT)hvj2J`mm z0JcSV+n~(jN0I3mR=TNp?h{TrA?_?KnG4r_8gsLkAN*DX`k2!IvfX1J(~2ZX+JnHQ zY@>t1DYC`e3x<*jbvOVA#2m zK_k!M>1Xy)j(H-2kKHL8)*?IBloReICk;XCbg8`xfwDZ}A?9qxaORwaMf}e^9 z5BeO0fY?mo^;y7yUR8u&H(s}8I91{$aVt|(FMD>msI(1bgD!mp>O6y{077yw%rYjE97b;VAS;VC8%{a|%&)tM>^?A2Bpq*?6e#;ng?OJxLMpbbq<|3}IL(}J1tO{x);Nc7Fv*Xs zQ37PcsRFz?&~G3-t3PuD)@)&l#|s9ZI39w)2EC%WrYq< zddHzeK=d_&bskqdKDIZQm#)7FRs5rAaX}(w%-Ulk8?8iF+h75-d&_p&0KLnq8r&2P zPCK0z!??RbyUEg5$#bNsjC_5Ej!vbNk#IcYBOU{mDUN8Je)oA6S9i&plm^yp#!_jYtf_N2^KtkkBP1bl5HetfQN z6jlWV3R^jlT+vyr*E+$0#1T|e4xMAoKKX0tqJ+9aQyLSA&5=g$hzzX*gew<2&Z1)w zyWFhK<|6Rdp}1m2JOltRuU;&BD5z6)vR)N3ASPSOYJ#SuGqkUvnb_)J>2B)YB%R(# zi(qxjkGU2XCrZ&=Le#J9QG;EPr51w~yx=B^*5`_)$RDZlsH%_&S1ON)_+ls=eyOps zg&<`}`8mGWk|#Vifz@^ZlS6y5ula46r4G!tPjoq_;il5?c=k|`#JpAImW@tVp6n*5 zX!_5N2mwUe7i{FXXzXnzsoHdGoUoPI>D$|Y8L{d5=+^Ngunf+GB&aGwY6F{oeIaVY z(D=l7*md=j=dLsk`!{zA#qWUcyA6!r8X{~?;XN2L)7J|`pk}S@Mgoj5W{#B}iMVL-zI{I~a34w#CTVG;VwnF66!w2z5Ca71frTvpx*&%6XWuSbGRUlRRJrL}SK$H{!eA0kyHrqG&mIc^Cfb-kczbZU`GyysP5o!G`9sMh1 z0fG2`Qn>hi;r9pi#SDb}*@4I$3kNWQz{)BX#&5v{0N84-Y=f{t$|9^_$ zw5v{}fe4b|=DzTQPTf%JWNUSIJapB3$&hWz z!Ld^#_m#!zjydL6@J@OVGT`3fgTu|4K{EcWrM-juePsbH8`P^k3r91`mu64d_tF|* z0U=I4oEit14s2ZY)1?(H_)n+3>n9Q~*-<)(A^AdVP}#B}tk-X1+X?*qsv@f&P29fT!r%*#5DbsCJ5%IU`6rOypfbA@UPDrca`M8B{dn8=w8Upk3)F75W<9s2%8`A3>n;Kl9ImUS9H7I*>@~Lq+s0D|P|+$6CbwYOwJT}1aWZc4chF|pX&4-VtRv(-a%^Hf7`G>>NsA@o zT@rp^!*OUbrb9h_PJ5!@QRn{p%mq4RR|aX&-tzPL+T{Hp!_KgH;bf5WNk2@e(89f< z-GQ?_fP1F3dm(e;@HwWqRN7_{oZ-qOAElf;@eq$4_bsPAn(eV?%_cdwQo|C-882_| z5HwA02eh{}Ea7vjy8O!A&(aOhISkhgohvh^<9@1LbzvqlFpPv9A^~;1tG?Hf0K|{^GHh#^R?qr8=fm$g3gKcWGW%zJD2Hz`%xNf+)J+G!Mwu`&hdymgML?TG zVclrn5lm}UXaOW*yl@WKyTM>*r#wQ~xsO!XQKT-NEi*6TE>b2ekUjNFs7Xv`S3 zPno7{*|o@t$WNoA^mNJw6eerupJt`X5x}Pk@~tTjObx$W1O2BEaq|{ z>x5BP`PWaBH*Sfjha28LB>79Y5mvjYAuGa&FlQU0_+=s$Y<6e~L#WCXJZ|C)8a%yHtQK3(8?Ez7Rp7~gjX{6@2GPc#*1k! za&ex78lsesoQP&N-Xhq4E@>|#zM-tFn?~vB(hw|NjdpIetPSNDxmC>ak~d2I0EJxj z0jq{fRBiOE9I)@us4hKEnF9e2|H5%y7XuxPrUo-{<65 z9&fg5*LGHq7)jU7`@2kU-^K)v_^PJ8Nj_AL+QYPa2x8|~b=>Se;2b&3Q1)raU8@lH zYuLGTFbCaktA2zCerE1WUt#>3h?AyDjfu*8B1(@KtL++HtYs zG0y^jWpgaOzTHRqonCJQohx2(Q#75}0DgiJ8tG>~g4hYYKu^@yW$O+!nmi)%Ls3sy zhZG=H7fq`;?H)9(Q$EXh4&AR54$qv%9uuEGTgoLo+(3w(r3vh|Rq=xM&Anzm1KjCX z5MmzKc2vjh*JC$yO4;ixUO&5ox!xswX!-P*;oZ6sH|6T7|IDA`A)`DD-fpJmeR3T! z#=`;gk;Ejkua%rM%RENd3(a?h{=1klr>{G=Hn65Vp>!6wOqO1BdC9xqT&+Ylb#{FO zYrj1&=J)-w0CpR7paM!J6)*35_IQ70BEWvzK}VK_JT=HSh33vcWs4s%3oYfIbFTgQ z4XW5sA<08)6tyr9F!k=~xVQP8W;{FIN5EF0vMLb0_2}fO(YqFVB`x6XcB%9d9tW{6 zhqcJ=vP%IIFFqvuUbkn8L6X5t_|}zStx>H+^9#jP(q4lr|32j`2a}o%`PG|=LFEjr z-l%;)&cud*^`fFC@gkMty%9Owjpv504(H6S?sfe}QbOwaJ_*JLtambauMu_1d$K-N z)>=4LSnedrwwI;MGwI)lzIMduQ+D-#fbX6*hq)D~BliE`bXEXm9C| zMy{0_qUebVN(OlUYTv~J@82pqRDr3O25h8k!*Z8ACKNf!DmrxCmHWB#lXqcxvBDA9 zGp4#=U3L3oTvb^Po)}v{>a?(_6K1wN&rQ~E-up}}(=+}E+LPU3lV{5gJz9uVFx9z@CdLF$qEDVc_ zGc83*?ClD0!L6s^JyGgv#kEfgEYQY${?$%pg$_!n!Od!WR}bDr`EdK|$&%C|vj6Z# z*@`I}qMa>ey;mQeb#KB4Ry{o$BinV}mwZTXn~2ljn%cv0=dPv&ymz^c)m11-o@>rN zt?+-Jt$zbpj{$4Dc$VA9>OiA9jU%4(pqkVC{*(vn5)q?D@}V(9US*_0_{6?lNXuk& ztS4T2ZSGZSNUR^I#30%7SD|vg%@x(PoAT}x595V-h_Yj8w2id9i&ekDgamCN$&o@` zriPLg+vVm#&;I)l_-JzV?aGTQsJ2G7#&5B6z4(^bZqCH^Xn^@obeVE*FdK9x4q~45tPL# zb{7>Uj}cDl>j}8(Yn@sCH^|j(W=hl+SUx@a%vMoNcgq{&8P+Ur z`Q*I#{kvuNEu|P84_vs=o6Fq3WQ}bi1=CSF0gnEMbs%yp#FkiN2Pu{MIGK3feZxv~ z6D1Bj<9@MMmk$|3{B-aH?gR%^sZqh;Gb~3IJ>GXpUBJErA-go`_4=Eu&E&S3i-(1u z{RO92XUbs?TkoFD)3a^9ukyYynU3u~_fBuP(rSV0a)+Fky;Ym*V!QSx6uqSJtetgT zS`b@l;8RcOSv|*M;3pWHPJT1a`7n;FQu~GAg+T=4Irs9{s^i#(drj(!a+EL7=hH)U zsXeYsnCC`}g%#^C9(M)KF4^4|u5df!Q=$~tPtl{XlQjYG=D5+&&Z|%tc$%-Wv(}3{ z_Y&1d6Jxsh5uuQIG7!d7W&0WT4etdJero)5#(r~OFU;}8kOIZ$r}OBEq$YzY zt3!%c7~v8#;Wkc}uh%1y7LlN%Nlw(c5zFD_*dK=snsZj`$>~ApXmJ$lft^1t`8F^l zpl5gUbtt!{T7omDkAIN|(-OT&9YOU7lxJ4BK$-<+J)RX5GqM>$R$yGp8$Y6^ioL3C zVvaIaydVVR4VRK2Q$bO>okR(15eZ=Lo{(u@f67WD9_@TBMuX17?`VQQA*Lj$gdtR8LCpi|iybZ|GeIiE zM4-}vMUasy6D>xxgLSuGz5vQlBJrYDr2A92AoQ!}aPMIn+iFYKH8H>@IAmX`-e4q9 zl6fr#U|YBnb-$N=F+TYQPLp{ZONXoaIV()ES7mtS%aSo@UBh+OY&J)}1)T$NzLyMl zAd4*F9OgoS=A*>Bki-bm1STq|aSBg-~`Fddr1#tc+VQ55*aqn~s+yEw6UL7fJ+)Of*5N(I*)Bp>;csz!mTU?D~Uoqw@^AXXhpv>N&B3ok)g_v|7IKA zg+d6| z8jniy$%RTVEhBkodaQERX?=PoRFsO$C|lD}s-&!{bBmCR^DcWrp4qMK-XMva~^jZF+p)r)710l72m)yt-Rb8<$TLkJ@JIK`z1$Fr~OGjKSeu1%W zMID_vBv^<>))>MSTW7B=ZW2|8%s84Hd{i-=laHDb4(7LJ}mE_K{9SBk&UEzsh zqhkh|!zHxN?^qO==E%9_^2{aT0l^axNpFh{c?Re-g#p7P+ST--$z?eog@FtS-we@ldz4SI9+_H^_&R8(AxcB*R0tT(o&N7vA6b zn%l!QOPEs~=7;+NpUcHP$-t&zhj=9bv9L?E*6T^4BWdB@v7z7w<}J|lSeJZ3LP2z| zBT(hU2Pkp^a-3^sshnpx+{YxVUkOWBt2J%uS%*qPC~w_O<@kvjh7v%d%Du z=k7v(H9l?rT!lNU99y7eEY4OsdoN6Uc!a-{ZueYE_2r{}*pS_U?`10Es&M~;HO z5B;aN%mBbGGj>)cHcr4VTV~APd^Nsb{0p`m|J9z^FUMg2&7K(t@X+GdV&h?5%~+B_ zN52#O|A)J`46AF&)`cNha7b_o?(PeBcXtc!?jC}>2Y0s++#Lc02rj|h-Sw_WckjLX z-g9>M{ceA!`v+lBEasCr)~HdVX1&t64WTr64}u0J)@KesmsmUgvS|g1wOR9BCyU;F zr_VC7n>RliyD&n%rbc+vnSrv1p;DT9va);OPJ5==UHisGtU_exAp$SY<8_=y4qbbs z|BLJAn!&Iu+S`xk9JCt6MUO|KJyuF#r<9z{oIGY$i9lMy79qkTPUh3i@PrRCqRMSN z+^L>_80A;~L7DxU`^J?YQYWS!#EGSVzna24xY9zUxe{A_vWG0 zan(s-F|a^ z?0s1}%J~|t{{G?WV#X%n)4i;Qm*g{=0pUYZo3ci`_uxKn@k~9Z_xRT3gwFxb^WARq zC^O}uAdE8MB=paMaB=FcJ!3Ix*IpqN4L8YL8EtP%10@VwA%UIy_q@) znU)PFn)A!uYpa)U&=#NKBGA3Vo){Uf2i||9^H4$eX=2Z|xQ-S9zuP7lGIhNz&zV5uP>~qHMa@$j%&!T2?piljz zxAn~C9MpCH_KD4;Fk|Iqy|?u)69~8J2$k!tw(|T@{@7qd|73+S{BTqwpn!xi~wnJ>*S~E2)efT|=+N{_8Hs%N$1tC~j~lhlNw$ZMDdkqkdpj6uC~~ zco|P(eo5Uvr0}csNgjruFJ^=g;KdBDw#hve4Zqr%Os>&9N3D}x_fzsS7!WLmgsfGu z8lR?cT#$4r_&(}ed_>oW4hW;XI$wUiYCe8`cnr<|W;|SA)@+8hSHhEG%x=ja$-=`D zw!*r%i)!t2&E4CZk%Au-d6XgTn3~5S3$&Jj+-{j_e)hQYiWx`%X{CIXU9CWjo|b9e zO%=Iy+k;b1^hA_NH#|nNwmdP6Fpe{@fexQ zK5(iXd>dhNt(m`qRHk4$OjNE=bmUyxlK8GD;iC_hlvj>5h01N59u|Nmhnk1fthFc*!*lCCDxsDE*Wory%M82s@U?nRR~m}sgU*_B zqe>04;_C$~qe+U2x#FOr0VgvymBe2xpqoCnq$r_7p=t024vC0OYx=ETGYyk_^|`mY zmu{Qsj;^=QcfFLo+d8i;c^+x$vY=8>;?9hkaW$ULFn6ZSA8atVZ?<_*-=UL6RO%bM zqjKQgy_WZW`JFYR7nzg9;6{N|$7=pzBAf+;DBwa*oLR@XL8~3L@ipHZW^wQo7%)E+E%tPVK@v#)JtgP6a zubWdgYYs}l2t>FfXOJ_3e2RVrcA*lw*=M-5_s|3BqFK>xQ32_9&YryYwi1wtqJL*v zZ4hF-nwBWgNPYo=evalVcxjxIkF$g06i;{g4(ud8iT)0fYd=6h%TAV$A$4`ow>?Cn zpV4krjT8=&a~Bkl{5sMoQW%iPZi~-q1mvM<;=*2BXP=`f^j2^rGN7L>#FZM8Scx1J z+EXg&p{FvE?Qxy;YiX8qy@OQ^v5N1j<6t3cnAPAp<4Xpjk7mdy$C% zOa9J5GvT_f5uTWdCh36X24nm_K@<>pnCL-4g5iK=P1>PXo+?S2t^6&*M6kwF%CQYc zf9@cT8vIrKE1Q#rTzMFC8TCYrC$6C+d5uHWwL4ErLyFQb1DM;P;ZGOG%U;hzcq+#E z?|CU@b-kPIv9(CnQ*Qc+)k@vf9!jL&RW&4l zZ8j9N6yf$^F@i}Sy(Lm@Q!Oh{PA0iwM&_;eJ%`g`qeaEFK=U$O{n|eB4GfWfU!8@} zC>h0>Yde|X0|>onx)^EZ#G^da-6ARW;k>qigO?R#rxjw3T#cCv7*G-}fd_myFXA5AEqt5;+R8{w( zXB)5WdFJ@}w$QDBH667i3g2fqs7Ym3*(ZekO<}@t$Jh(4)f>5pZ4o))^`GD`E}v|e^N_q)Y?Qtv03@w^E$v<)H=vB!tFhvJ11egt0CP{p zzr#F~oH1zDR+&e|HFFTg-vFS}+T7D`H<8DZ>#%nZwi>?)s zG?EAz6TOwTqP7@zocM_toJG1)EDpESqF^=OuwV#4sIvl!sfjE&HO8>~ zn%9n)%}bzIM!g8t&XJ&hfCx@xRUclwF&t#0o);^1ZbkEm z^NQb>3ah+Nj*Y58R+v00#2I(X*iKk}J-@|OdC|&C0d|(Be7EQ5LF3ly8{>RL0WP%e z#o)M&o=ZVU+%tghrd@GLVcv6#>E{fe|2cm2E1waFU52DP3}CU9`5uxh+CJ$#=54qk zKYaRwv=Y{RPkxmwj+Lnb%Fc?c#yw6{%@w=*s!kxV7JF593I-kXf)W`@?M9NKU82)G zWk7#0+bqI*w}BqkW9{VevCBHaPQx>#c{Hhf`%COOH6*7B^%*^^+^RGqN`zdzb6Ee2 zGiK3`>c#*y+pD71MC@p_qz?k)ZQGE>Q&72x{R>%lQsm z3AMAU_H&dok7ozyLDPL$()nkq1E#ujkHGXi-kqxf*HOl%a+?9TmVf|^Q9{o4CS+r; zXIT0C&_u(^Wt-=rRQHpoq>toFSeMEMjSh6Z9!GWzr=8f2ItSX#+~e9`nxTg11NyC% z8~a+^8^7p#QU}eD4SmtAu5A9${_TR6+Z~3I?m(^d`Nm@NHmAKIY`65j zTZaeJ<36H^aE7X@*?CHP$-4d7@TegiWy|D9;bm2l4XP2QpMh>$o6Es%-1MF1?B~mI z`|vnvMX%O88^5N?p#wzLe(Ih#(`un!m}mUkt{^G%%)Tj)(@^fK05F6u4Av7^#-Wu|kR;w&<@IVP$H#2dWiX(;s` z<%3CFtq(2G^1cZmf6H{(ruZ0}-dgAL(H7lhDI^twZD&5Rp=kVVp#79pHGV8AZ6&SI zYGFZq3ii4S0k*_v38Rzsxb^Z8j^21AUY^q)tD3;V6wpFT>uj!%Igw!*Op}TwsZJY4 z*uJ8BBg1W=Y%N#uqfntS=2)5@pidy&E3P1gFcBrsQtIxk!PtT_EG&+4zyyxE%K(IL zlb949P2{F4mis<;e}QBa)Infu8`frLpRQ-UvH6T@q?^`-3P> z&ANVgpqp8$XVtU)qRBuFEo9EVLKQY{ort`577|`TUB)jvFFl7l(mG9Jz+1&?w7cyW1swLU@^1)yaVI5sI;H{9ml63^QyaHC&pSk;u zm6-TEW(nHp!S#5P*HBKlEON)#iLALStObeOzB(||8G|c!(5Md`VB3D8(d;IbtI-EnT(QZ4 zV#o+NSFoGrN8d#Qso<{4$Nn*u{;t>;D-ko%8Z{%t2%Sd4j`8;tnI@G}Pt{smT6wvo z93m2UEWp-lM#*6e45(7;X8GW6`oVOJHq1*lFHGu^o&h{^Pu2S$Pj^EeI2)DHZ_a1S56fO&q0i9_(-`z42Ayz zv%}Qr<*1$PTl^elcAHNO#EcbiEseCXyRE4q&~w&|Rj*ovO3GZl)rz|hjY;CyNvpAr zV@^Na30ET-xmU)YwgQss2I^quTbU<38ru-5?mqbp$E?`Q1__7Ak7km;JS$*%J2lDQC}#(^gwXWnIEXlJlw|H#EX5wIKNokN_p2| zJvyZXU!%7cRb&`IJ6NSNB%`Y*BiE^AFqiBl3K69RJ{}xxpdJ0@E>WQaPp&sKvL4Z6 z;)-FNJm`Eb%@wQ33^resRzkE}k^>B0n7zj;2m6SM<4`(l#S}?Yl;}kNM$GQ+r5@rV zTqNWp94@ur-B1o*JxeDKg#33o1&vq+fGj77ZD#0uzp&2raAU z#up%5AHN=r+y;5ixRi=*lL`G|3XuJfA8&*b9d+@YzS$4C;0wFs% zqf>ns;L5(V=6EOc>^N~@q00iI>Hc<6lWGZTDublhbN<+vK;lR!nsM{?ui8#JR{~wNRXKdf^7IltW0Vj)qKGK`3Z-XDD%3>Db`(?W(<1j7 z9=6*r>*h9Z*9)(r*)CcOTv`aw8bLUPTV0FNVKx`63pI6I>uM!PL8SzWr2ZvvOBeR&J^(1X{UII3K9c0Y8e-5ZF}J3pe)hM*jN65zFL$ za4JbH7CN~*o4wYrf~#n3>a{Ef12Eo=%i+5$^Fq#CXP58{e?uYjy=~E43NbVe!mA2! zitOAxv%P`MzjWIYm#?(a(p~=KJo+NMn43&XJFUZfzhG(;VlAMWIqVCv(B#03%DDL3 zTdrk>x~nt&C|v@#<_G13p-PeMIrw8QE{25;wxFD*sc~C>lH`puH|h>Sw&?EwmtaArqcrH|SEIeeYA$fDh-e{20iOo*A_Rg(kq z)}>wBLrgHbS-TgTNKZ3NKCeZdn|zr!H_avh^XXwSoSd+t6ha1_yf z{1UUEz<30|hUjV?j%$Nwp8mdtF#*+W50h*q^i>Vpo6unZx)(-^CAV&}t>$SJ%s&3B z`?c!&_?LIH=W-=BFA7BrSCQ>X_-|>}I8t+zz_v%XV?I!&+(p_7`D-Y#IrUInX4EpR z=~p=kV=CmOj+MQ+P2B+vV$%2aOW3U6A*Ye4-{251-60Mx@{h$kVNc8L&_Cfr2CpSO zj5zLlLAgGT=o$$BLWIOSN!e0BkoZ!vF(fvOH{j7SdBHsZ-pQFqWv8+a2Uh&rVce6N zxZWZ6n_0$qzGFpWL!3BxXQxHB) z;kuO@Ir2Uf?tuXIflpp`<0K(-xY5inlbLAZHOoGn z4;@91?+ww?3M}q2!$Ia-o=K7sEtGHmwz{3;dOH;+bc?DV-3bJp#>*jw?vJrJ%G9z} z+K@!ANlsQ}qSr3CKI1jf;UG5AJ!z!m!$`rB?YMgBTkd3$%bn;2=fb}JTMBW%5HohK zy7q}7h+HK*d+T{{zy82UD$O5PhdIBum6~*`bHkIcuUlydA8A5HYvbcTs?>N15me~0 z6VT83*sx@V_HwzATl=Hk@lw#~9u#@Vt<5Nga6(@t4ACZR;xH*~TauY&$vi-(7uMB@ z1V<-UB+UkQ(;aowNywxq0JkWZ6ETV$2~ntkJx_crf47Cy=QVfmsZ@)Ph9D*kxbJxo z?GAzpurVvj>_u5abAI^S11qaUn1OIf-nVYVgBa!8pQy~31%nxI~%fG7JjEVBs?NNpO|^=SEDstfL+yhA-x#A z@H}NVa8qx!jDv18UIwKfnh@%sJmM)%EX2j)W0;g9*0;nUHe$boMtdVY~Pjfm2z zST^Xfj-`XoMC*LK^nvA3sAF;B<+k*Owbge5Bd1xOjuQ!_!Iz^kO7r1uwoP zen-+9U7hGYN>@;zX%K`R@2!mqle*8+Y=llL2@ zX$&58mrEWxg$bUq=Et`&7y~k}a~|F}=-3?AEqwfk$fC8Po|FU%X)v${(B(m6S<^`_ z79{B5A73Rg7b^=Erh|rRL;=iOI|_%vgumV?o7tqXgE8V2U(&yi!1VUnZS|2#B)Zs! zEDv(&I{XGE88v0St9$I7DE^vJ*xVe~I}gv$i)oKq`jeCH1B!!doQIA2o~r3051!9y z^}#a|j@2Dt%fr6rP+I?ZaI9dl^mt&bj-~1QztATvk(8=RLviEsUNx+d2T zzP4>0Xs7EGM+0Q$+8MG#k$s3h4}s}N1@aZw=4I*of;eQK zt9&Lz!jssCM-OfSY?@lgs?y4cAQ<-agu=a#rz@#l?3VPDZOYb;wIM<|7SJNxXNCwO z(=!`N7Atp`eRvud+Y|UMZqE07>M!mL)W;{=C^VO%*S;~(EpB;T>x&-r5tjNjk*&hHlz2;T3^t~h zGt-O{lgqXkW3JO`(0srndDR97$09?flyvU$0;pNad|G%W-Fmqgg0pUe^tV=J%pbBWS)w}-;n-(v zT&wtXaHbH7XK6J{B>Wr2jEE8_j0rR**G;4Q$zD;{GGb*8?c7G^Nv-xWw|o?@FT>r< z@eJzo#yyu8^Q9pJ_#%Wf&3)}ddW(n>L(t_;oPgqFQi+O z*hc;8EUE6Z!v(b|*+OTQ$Qr%gVGt)Cl;-b*m_6B2#PZcehmsCw4I9AWx(!`lYhaPa ziPbtWVewRYh{c2KJBrH(jrAM^4xA`ArASdf$6D6n-&l+94wvyLGd#p?>vB~3L%e!m0<;lIeu{vcXW*kG%>|By+Asg ziNND~Oubj_{I$KvTO?6{E~zbKQH@gJNcOK-q6&I@+>vtgEDLTDn@O)k=j~uYYL(Z- zTC;9cj|Q#)3e&V~3klV8h|}F;(pCw8uI+6Z47D|nxM8>>&jo7;I%N7!^422Gc5gl% zlV1mvj#EC%S(~)dv6ot-a4~hXm4Pq1FC0tRBx-giU0^E|SoIALJOuQFs>UQ~b|2i> zS$vS?wU)N1O&#l3w}Bg_*|9UYxpch*%m@`NBswo_sB3Q4o$LzVOiH$sa9K=_#Udwa zDjZ?~n`qQq&fQ&Jb2M5&rbdpoY)OrjAZ z5%45Qo0wKIeNj{DXXP#$ag#A@FC8&cLN012B}C;!)|>tw;1km8g<2^bA(z%@ z#f5r*=pB}_*@oV)EHi9yfDeSAq;|NB4cGxH?TyZLdc^mRN}a|Z(CzS=!E%>eFB&0v zcN(ML#snen)J!+Jj$x6Jk1+O=Ox6Uh>Mdc(B<$o`1jo{7+q;++ydt(lw54{&*6@_f zmrWHt2c*z+LGwffoOT!^VHmY>FZ+#;H#L~)LQflLe|k4<-}cm{ieh2mm0-X_We+pq z9dht?9(B|8LRm9GqA^E4(^DDrKIMxOXp*r5pCdux*e8}CIMr!_Bq1|r<&?*_im%M( z%m*-Q-ocCh0@emN@E|pH;L3QTzZz{*1s>Wb&u?`Xv8<#A5N*RMI*CH z(Z!nj#A;P?4aA}_7Uw*&UwJ88T~$26!#DkGcPdI}jp zwF8$?N-xGIv9Ztz%`;w7HOWC$QrYK|RNlv}dQKfKe7p(Ehnf%G6`W(zn!KECxkjrA z2KS9m)5JG2pRo2F*RxxXzI4&jd2TnlC(k5tE822bVE1XK)m3r_%64ALW|x<-z2VyF zS!YiLJgq*1(&5Im|8IaP%-@9teh20FzXzuL&@A{rYaRfZj6bvun15*)F#pmpVE(0H z!2C-S0mx1J`MzJ82teA}&!2x>AD@xsmnH(suj{e=x*pI-?#KIpHUdAt|GFN~j^gLf zzplsf>v}9duJ`{0DD&f1e-~YTYik=vIz^|qj&8O__;gZc))v4>893r=GB7gIGP2S$ z09f#W97Z4y@26-2(E5#)kpcKid{&@G4gJ5=1@zDI8~^w8#=j66e-dMv7}Dc{tIA4{~wUg|GU`yBeYl+pqK^#=&Zv2+q_`{(uRR4#0&(U z{d?yPGvgnGJARajKbbd-zm3gb^X7N4`FGBnzmLs7!e#wiy#bQ%fkuJ9>J2;4rH6?X z02DQ0`uUQP@qh4~`tRHofi6$%On)dmzoE$fcbxOz6lI`6DR7?sDm;G+5;L%B|4R*q z|B0gf&jji30IPp$<@#IB-~%;5{+>NB=!%+y5y>-4CO}-}PV^X_dK@e)K&HfZ&-NdK{~3|_JE6iq zwKy|=UwD3I4Fe1NcPSWlpgw>>GEI(_{ zZ=(ZjUH+xD=l^+d{(7Prf7l58 zc!Kz6o1MRH1Q=MqZ;QS+JB&b6dNvlI$?11(Gy0!{|EiVhUlJkK-#ljiFDQ1bY^=<` zrPwWMFGd0VJbg0T-)2BG^d2MfsdY$fz#gcL&6&)`#stkRX~K4Dfv_XqUMnh7$M$9% zwJnXAL-cHq#kTJnqlPK>u5IsBzw>DyJIUO*hzGLl(zj&`GiA&}Guo`6-|h33pXIem z@}x)@5TbSK8h{U*UYbILX{bY(GY+kyMnDAZsN){bu8Rlf>)kA}P=)(8nz>hRO4W2a?C3b0ME= zJp({c!zUbBr17+zg)07%t_4jFJylb~o# z$S?=j%h7odYiC)wX~um4Q2Jxz&QC~)+(Fblr=sMDA$g$$E@N_2a!Ru4fs(CKcNx8! z!kiz5zig6j=^H}?)Oc^1&}t`BE#JuGDyIr|Z-A;^W}siB1yKD z=Dw8I0<6-N-SM}$mv=-)wVa_{4iLT#0PmIf}NP&RNksJ2Y}rD|mQ z`v-;wphSQpYn~S-|TZY70W!o%enuJILu( zuSAa`^lOlDzV_iJF51c`?+4eXz=jHl?Z;-w`UI$fq`O0w^FPOyHV>c72wl*DCF|f{ zY@Q5YQI?U~ochd`8u%5FF=+09C`s|jVS`n?k+_&V_V@SkVFtlWOO3CZY^LLF@wq-e zemb0P#8hhQ$ec`vYt&Iq^E24yCw*_G8{w6Gr63Nu=OOQBz^1fl$O6sS5N2DP5wQT> z?fG`WMXHJA8Nd;$A>;5W>cBo=Y{Et4Lcqa=OU%ahcC?Fzm8@zVt}L@mg`=6qg{>)P ztZ{l9D=3E-ykyREN?YFU4VqL8n0sbc<@tbHcwAgMj%`eBPp4LFX8hGOAY>nf)BVq?8&g_-WlZqv_#m2VT3PNkN$&?fPK?6`C&xE?6L#d^h`-hm>dS{lH)oNL z_2I?Soakik`-aT}qXk51@@xqZCtp$K#fC+@aUv25!Zw+%JFdCw(cXoDO!efO~j zbnZ^D%A+D%n81yMS@$BPev1ySlagE5>ri=`KVHWkx(HIg=_;48l58NncIlUT% zsUk#(gkW?7^LtPma|#M))WipI!RX7FK#)%#_*j_ko+DGG1~tBl*zpArh-qQH>+v`w z`QeI%$N1h)s-F5lRtj#gHJJpCk;f2vHYoOL<_(1%J$%|+K*GXBy1xd_CnTDn&lPY_ ze6f%v0hdxbo2g^6nOGfdSU5IcxNdHrWZUl-p-fK)YVAfLOh8t^s-#h#J6_a2-9*o{ zE8u0~mCfB8soS&`42#OArdJ)Vl(l5W4pZKPO)=P2bL`1mshBJos&n@p){k@RZuSpX z#tO{TKP_&a>D3Wu(0aUD-Z)*yO<1D(Y6HCt18I46s=_d%Dm`ZK6{H6UMb-pq5_)aRu^)T9V?bV%6V^s@{T{Qs~Wq@RshzU zjMm&l;f^}rt4>uP)U``g9>_RT)*Uwq*_zM<$^Z^(X!&hdYG9ET_~SvwU@y8g)>OOn zf$6zAYWSKrouNRTKd#VZJFbTa?#YYFql4*cO--WkCFqB!ikyV@$Pqy=4usD1fCfmB zNh0g=4EwD@>|O|SPpaniR-PG>k=i7b=I@Ll@&@eBHL4Me_%((EH4JX=kdDz24)Q$n zGjGlwuYrcNyx!a*@ZVI9hOboJ&Z+9lPrSdmxqG2we}kC!RP{Tpa1Tfda`v}_i*UrA z&*q$kJDi;0ZavY~KCGZx+Qp1(D~#$!&K=MbVRm}j%=EcAtml0&GP+!gAxp5WB^(?e zSnpKQcQhGA3#U$!UoDK2_qOMN#3e>p=fw!41Tu^h8|2MCWytd;+lB=~A53(A0Pjo0 zg?gRtNvFAj^cl)sM-H49^wPNIl=S)~U8Qi9Y`w(9_>ubsa z4UD4hVgcNmkz7BH11|lGsi%}SnYRVe@8eL4)2X}o+V1*o zL+?0KqZIG!qdHFGg<0gi3tZ_Ko9j-bc@R$M!k97hy%*Afgtmgw@9o%M2b1TfB{V=D zMh1>4k=c`&E2Urb=8s2eYIqhK!E*W1qDrHoSXtgJ&h4*oO%|-rD&`;Mf?d8I^{ z=Ak8Os-TQuTU56>R&vhXj&^$7GR3?DI{b8cznXN2QC zXvJ-rKvqky-492;LhZ$}5GAsQxrYC6@MtRBQ1muSUop19e}sozB$ZHHNh78w9~ItJ z(OkR=+jm1YC8j8{h7hOjg$cc9A^>4b*%-J~$N|M!l2nLKb=<^(7I@0@P@>Q81}ja4 z6gq+|cWQ~$2YkD4-jvkK%|=#&f1;~6%}VT#aIV+&bgPA;U3l-|7@7@P#Dw^THYyI~_Dgiak8!a}p9z_>T}3OV(3 zYlWaAimNOv71QJ6=kkZi>zc{q0VH#)EuGxER;lBJO$+eCKE}j#!a;|;0xy?)3jyCe z+#K5TFG4(wr%N(MrQwfK?Kz5R@#pkeT+JU!(E~tDK$0K?U*VuTKft)AFn^%Kc-Nu7 z!oaTjHP05k2fn2FJP812EC8GpW{ka~lA-J~$T1t0x#x13kx5p(dUzs;`8yk=7Y*)N zfUF2!>K{b_+2$`rfSTvE;a#Z>uRI|M_2nrGsRTlhseeVdR?9$(FnA-@&2g7yha7(& zNnoNeSa~Qc0?LFl4$4bP`L7iKFv>3?YvY!XEfiIGv#2^}WWyrUqABphk`|k`pBL@0 zv%d|7vxfflT~j&=2j6*KRl!ox$j&!ZQo3T8c#LUm$!*c|4hzu;j@QE*G(NPM3?(@G zbzGHF>BQZQvYc~p&g;G)WERreGqmSq+;{fVM>r zBz=zr4J8+AT~!M|P0Ny+C?ohA(k->OMHQI1-Vxc6N}~bbOSVN!wlRKLpEMMAUQQt_ zb!UmJRMJmk!g#CKBEmU64hnTB($X9IS5XV9YI_L|E`)zLk@u_V6I7?;>g^$-9o{9#-d-S#ubKe-C-n6iE znx0tdP!IOelh6xtQP11i_Ay9j1 ztyJb#m&pX_D}e;~_Di}>*RNy2gd~rN*z%QQ48Qz7FW1V?V&9^FpO^3e;sl*HH&1D~ zY^#TXI09XFUz=np$pF$TMDN;g3_TKJf|M}599s)V6W}zj^o5`n1$5Nj4bQf|NHVSg zhczx{RO*t%QGH4S`croM!bnCp)ByW{P+%WG0_+1Mfqg)M9>0<2%aQ(U6o_$$aOcoh zwf3Mj>*FYpEi*cDD6tv|*PSeK`~|Hr<6{H@HxGfFR{_Dg*060CP?h>n{#`pW8rMBK z(o|y()47!e*ExXoX?JDz(ygAdZvniuCN=fkUg@o+=P{-7euvfGPAX%(*4K%hG&92J z6S0-tBy$2UFxS33?kv%9l$Jgg5Wi51iOGHufKAO6+l0RBZUm!c3J%=x~g~ z*lGuS`!Ku%17_B!6@j^PA)_8G&#OeXA1NlR5bweco*M>&M&boc%zEZTCI-FO}3#odCi7A`XoCP}1^!1WRv&RjmU5P|i zUZtAft^q>ywma!H7LZFNR28Acb@k3Z-L|`#fOSyvgiKrE;u*~ zJZ|+apIwe8^V_yd)BQhlk{Q&E!qXxg@VA)9RkI3MZV~8!4tMubBkC(dW;QYP!mO00?^=54!_Twg49-~x6 zIG9T(GC#jUW^o$rWWDwrCE!4>YoBN5$2;QqSa{4nRPTZ`wm=loTIoD0*!HlH^>J*} z?PSrx|Ec1&?{&J*GJ6fdSQyKDA!T>vrr5x)|SY1&<4vVn`{wb@LpT$1eI))Vr$^32iC(fn)A2%mnCHej4rb~&Fb@Xfj-2QCgZHo|! ztq8En3m-VEswztnt|bFs-C^l`s8Bte^dl;^Oc!hDPJl~s{%ndM4g2lTU)(Vkgp(R>S4O5y(`-B<^=dfh*y{YZ*sG@Tq48AyVwQ`4XoNva9 zNKLshq;j~(>RGk>4ow}?d)=~oeBiTes8tcJm)nhO@9Q)uuFo~pX$rS~1xMQ9bvuTI z8_s3_5?0d@3CB;j!=K_s|9Oj?C4Z_6(4AK}L{byy#26>`ZGG-YdX11gs#yqRQITm` zq(3`Z3svTr_1!DfK5{#=2(YEa=qz%r>6E-EZ8x%FM}N=zeS`e>y36>j4g86uNXN4( zWEd!cW539Xha$9r3wLnA3rbj5YaotqkcODfe-@^DseQ&KQ?@_2@S-WeYRqTNKqj-i6YlryX0kQ{*M*^;H}TFMMU^OB_Q;*$ErZlWr_` zY%qu#owl9D6A#)o=_lx{JEUhyq>RANpzdX74*Z0Q-r~Wr-N!S0*F_`kL8CtD3%5}y zTrE!yo6C|CkB;wx_10L-=0OkHty+>#A`|FIWDGoIy7|7mXI5_-n@z)gZ)rl^muSeY zd5jUHuh&xuM%IY(1)Q=i&52D)*C=I377PL~E|3O}O7<6&)<*D*$)+>} z{VDiIgHzxqFz@qC3ad~g1ZN*t=>!7BUB=At)E941)?J`pRxy( z_rDu<>sk&Nf34I0x|r0C^4?BxNZSIzT$opEY%jPGPgaI#NKEA%S3JhS6-*!}mC0Tj ztTe=$vkT|RwY#weXaJcce3K$1(uo%jXT2w7^7bRK1w&f55q7lJ7#Jb7T9@%@C}ls) zVXO^1I%Bnkg$9*->Bg%%K-)^#iKO@fInvs6cz?3+OBMbdk`U^(C^cIdpaY~@_}+vA zG)o9+A1>_~2$3}*Rx$Ca*Mkv4Uv@^wl@^KEx}=)J+aC2#IA6303Qa#%a-lX9C_s|G zHq1Xr?KeI*oFsuFSuuVa?1K*`m;+t7`tdDHgkP-d5mRDbt{AjVB1G(0eIcVAlOEe^ z*MTZf*By@W51k|L8AXggW1N@_P`AOYhdOll8J>Rl2|TUnUMx6;;PqP!GS=(?K)(2`v2pw4Er%Eg4TKBXE-CVe zx-emo4E9pbN`VQEksb&)ycv3NOR&WU1JW!o-$K4mF(|#)Y04M4JQ#`WTXJVX4}CkN z%U>WN2Wil)#w1YK3g;{(BELZD2KRDFh+DEU6sCx~rm8Wd#+Dg(v$Mv(%%BOy`HKnU zFq&CLMmXtOwxdY3aa^aqhbd`X&D$A2(m1|a7HoJPRqniakUi$u>0#58w_nT|Zxa7v z19|`522z9?po1g-MFcH`_!R(krYSnsKvMiGkNy|AYT4eS(F zxww|^kkjOfj<`tf0`HJz9H8XvC!^xgKexXXue%}|=zrVg%ju5ws3%_cRwD8a*^@`L z>m7+@s-^pOq?vW-fxxvDiC_e%V1I_tGXG)hF4;@@C%=^H8p)9oEQpbW9J*YY`aFxF zNop4OHU(_r?$iPngr`8Tb>WRk=FgEf(*B-z)68k>eMOhl@Nt6Bt`glFY97;CF9^)h zWU9F&BU2#o$W{d@YQ-6!@ZaR3AS=Yh8&c(L6p7ozT7LXG0>>JnLSk-61~IZwPmO^p z!n2VN7}hD-_$)bwT`Z9Svrak&qeMAr!>DdgsiD|Sdk0ND^2z1hS<(HGx_jZpPbw*(1O!($gpG7(8qv@|C&=?3PLPJhi$EvH+{P*G&-pJ0NmrX!R%g@DTL+e40pe3$ zb_56QzV~Xl81aF%qxt8rNnTT+xS8Un_i-+8nXo)rlG#gX!<)c8N~sS3SQ7R(i^8xR z90y9jknRy%9Da_U5^m$J1KF%0WjloJjGab7 zwH>)VgKy)X?lY3d$_&NmI$=ZBhHK~FRZ$s0rM!StJoZEdy?^yZ8B{S57pWy!|Kh{G zGMY^yrDE1(SdOLFoE$#)7634DlWND9Bv}Uegg>nZKgoP$3ZzJwH$X}snYZ+rAO@CE8pXc(}!=}rCfO5{^ndp(jqO0Q3QDz+08FxajeMl6`u4TuLrY&u%<7+5Ji zeyUdq(7*)9J%~nsRwDjp6C)#Rj|dxfz45eJGERx zOjQwlp^(htF?6;sl+=s)Iem^+8qyB{TDq^FhVE=`kK{wJQY*o=Or!joz;U8cM8kCa zW95v3mNFTUMkoom?BmiZAZUAhHJ|NW{V*bH4=i|;pI6gldSWmE+Sq8X-LRQFIhmY? za*mP*zmek{i(H^V7CEO4ebck|d@yD_j>KCI$gT?cs;Tb^`_vC^!D2&tJ5=v;f7Q&i zwCv&0Icy^1zt%(bh(wX0zZqhXdN1XvEfd3ZMH&Ks{upnX=8*YWyO~Oc`|>(y-Gx&W zdY_i@dXg-?^_y0g8JFoo6yA3`$ZMYylH|z$4K;%G@0_jvuc;9~j=}y5%}(H%`VWc% z>n{oe>n{oe>n{oe>n{oe>n{oe>n{oe>n}E4+b>E4+mGx0KcP1K_^{2j z;8`~i`1h~GVf_*J-^be;J13R#nVW9^Aejg(M5W)Uq^gk^~f7cHGpFzir3_vSRR$xyD zg#7(Ak$^6ywCs#53~Vg_F^R31>uYbO0RNdGCB^mkGE4Y2>e0t3>s z`~eK8SxHnM<2_UPwHnmLwH>4nG&aBhKkRaT09+jBz&~O|GvU4o*2rS5(-l@6OlSa!J%yz??j#ch0v z1g~yBXrOUtbz~IG`Ue=$5)u0+7?66sHLZJ#ZrSn)*6=$RkPq^&V8E;P=c?Ob8CmoD zsAqNZZze1dK*4=Y1G368aocbE@80t?L(>M&N2s=YRo}WvQwaRHJzB9UEQ0WT{Sl^dxtFm<4pC6l%o=g!TZ`QcYnoiTuXvu zvwYeehT#sQK9k4B`+Uad`6+1mv1Q5{<_6E#CbiwCFkV{1t&~sWrh%*+A%$idQ!mc@r+wX4K1U#p)6eX7FaX^6V#bY-a6gao172 zzSIi_3Thau8l|TCFEwpCj|A!Y*Pv>AEUaX{Jug1&mdG=pv`BEy+qLscE?SJe*z_91 zG3!MQkmGo{@VV{%vqffej&P=HLzRkrb7*_+Dbi3had;(xpn1q>pMs_RVv)O9{q`Oqp|o8O>N4aZ63^C0O*!N+vh+N)=9W z^*$bC>Tae|weKWSRmT#Uh&*@XPZT+lHy-XI?C50sXo3@*!(JVulc>-Q z>27XszF3TdMj!IqQ>Pr;-yBRl4t+{#9x>fh*LIpw?mC`e358iLLC~b7*Ch!Yo`EY~ zJQ|pz65^Vmk2tcfVl_zga0rJ6&*yWD#?d5Te@+sHksm!xk&iiA3K??ICL@3w5q=~_ z)VKc3HzcO$bGKQ~`*gPb+8gQtt_cK&ZwV0L(;JzMCwJgcvM&th1u0^^p^0C4c~*TS(T)NoT&F|y0&l;wHc@U?DA*?f8gm;TK@Bqp7xhyQBDP5fCwozs z!~!PMZbuO$uXDJ7n&IkR&7uu)#<-#T+zY6}tX+3?gXxtASjvt49dA?Fenel76UKZh zPV3g46_s^g*4vK?x_Vdd^i2cheg7ACXB`#SmaTi-CAb84 z32ueEySuvtcXxLP4#8c51PJZ~2yVgMJwPB>UPbzJ>8CoYQZ-`)>Ci48~qn?5g#x zx#yaj_1oV<5vV?8>FuP*|B6>`*%TUXnAgpj3YKurpA~B00SGs4d{$eYMj{fQt6!5R zAdiL-F5#!gZHyZQFa~#J({$}1 zFglcn+L#wWiqq3Rz^i9{;ZqHHCUuEN)!QyMUXs!%4V`4Tb{9xbdfzOvS9kJKvY!x-tCoOqv^6@k!TQ4u7 zNwpcHYr+`E7%c`C?M(1m=x1OyA|qUEGXOMvVq`Ugye zzeGTLCeAW_W`;N2ru#jljgx;YtwDvne_|lS3u=j;s*U`* z>VoMEJ*?|+DNheLD8b>mkAtGT`LIWT_qlJOp9(u>%)l7*tYQ(p^*veerjwq#`JBMi zu(X+pO3U0k^3xrWqtpm2XgTSs>|$86^kfPHDzqwVd5$!Ghz2@4M*kchhJd)60g)vT9^c@af>H6#L6?Sj?(NQF5mGihh@~;T)q!60Mdq~u;$%qyRBn5i*Tr~h= zdaofML5B`}Psp5J5V47WQ_- z>+4>vz|T-|)*4Ucy7k=ye#Szs*P9@Hj&1(F?i#d{!XQ60O1~{U01U< z^iP4S?&JN^V4sHNsYQ~m-wWt%sDat{$!+S9r=4InXm9$%K_xbuvXZ0-%30fg+tJ#XZw?>9Udjj^Mmi-$@`(V^VoH_4F#G!B8}Ue}xT{?B>^F)osF z!}F7m6FITM3tj9BNBf~i-B-m1I45jU4MSn3Zf#9_jO+Q=`C@rxNq2hv#KLSs*Kx7N zP#AF(_x=E}^N>NDsr%ZVVd&Q`^#R@h&9b5?5tbS*ERXa|wQgvw&9iOriCJXj`A~fa zinU1S%0&h~1DEFd`Jkvz`Y*vxDmbB4hT34GWpnX?^?-QzCZJH?(_1*a?4&3J3JF{rX}WMwtDny zoM*4FMC3clf?MeUx(NBPX(SW7&usVCYxkTZkXR6jmFIl!Yj z_0}*bt^kY*T!qNq+Y!>KJ8(d9#~9tnN`XtIehmiib>o6wV;6DyzNaGT7071^!Ax(k zm66ZD7cBghoE!(Fmb*j%;$qq{;EUTqb=>rePS_W7o{9w%GnPIz8Jftm4cZRp8~OI1 zku$ZBxd_76Lgd$}M4U~hwslIdq9bf|>z<2E(~y?+RXS3>3t)B2PJVvD8%6$tp#$rt z$=c25bcMvI)OfU` zE@0c(wi$b>X6st2^QJvJW;i0W`9E^R6r9Rc9}vhVZBuEP;!d%kd_Cc&Y-|#^#jx;9 zOYYAkr~Tqxwmgtob@$*)4zm`_F_2)?ugshd_ZS@Sv5JL#=hyz zY9Dofok!JHmo{nH5%G&4Q(D-gyn4)AD^Vpm|*g#l~oY($L5u z!x(ra@aE`OVUcRcC$$f~IfzE(Dos~j8H6P=AWQ1ol77THuhL63e^^}So<3?BsLr2H zJZgdJ~q0} z1njwn>NR-_$8ORB~3b-CvN_r(Iyvtj<)4;gBUoQUq?k>v19l ziZmuLv@Jp`x4A%fDR8!&tk~qk()wI@uYV&{R7Q)foV7cCP^8piHg0h5^re9cU$l@Y z+Q3F*U+z7$NRd%vM80 z?08DE6R=J@jdykL2A5oGxZ+Ug0Eh0GDGnS9mu%24A{RqaF50poIA5Js?&Ph{YVnkP>KIgk{XIIOTcrOkN)}ai&l6Flx8qsXD6J|?$+&i5^x8(%`Sqwur?YVs)e+)MPy%-OWKx}w#VcZ6a;mzPMbOXNnQGM=X zy4En|7rjRDPd*Az4bNrq9>6V3q*5mJ3Pd2+q;)<$`rph&;f55;9eVAIkmhH&T7Nx1s9%m95klo3=tmV2MT0w+ousamT$QR0!&dgx%~ob&cS831(B(N>+s% zVCk$9A!>=A#ku(AnPg$j=ZyE2kzXnI8fuacZTA{FR~_ZN)Brp|PPRNHy6ZQ*C69r8 z6?Uk}Pw#eT9p0EA>mtiM?aRF*$;U0kXb)tN2>Ud*?&D=j<^IaE?;b_J8L$13eG8tN zbN}uhU)tQVk}HzQWqoR^m4IfleEyM;da{K#3;C7B=v;OfT*D#G z7h!U(Yv=t0)GDo7pHhJep;l#7jIs_JnLyh(iz;nI%qafW1fHBKV&4j}^)SxUZcqy@ zPdhb*`#`^Xb6HyX)G7yUo?G3l;q8b(moSt&OW45*l%55_d!KxU-j}(2Fi;y-cam5g z8scd@LZC1674A>3vLCGFuSuRjsX{2VA=7M<^+Qq9r;d{Ge5+x2au=UK`M$n$Sn@0Q zGWb|S>qk$G0Y-B^k5@ZIQnlA`VFsq!r9$h#H5f7XNQE{PEZ%cJWP|@fv{56PPICEl zXJabx9*B#&z-4VKF`|{a%Tp%eR;xwUuRXL-?^rFL2z$-wjC8jlL(YJn0p*-wZKkvW?E?wS^x$SV zv|0*@mNpl6{|}fPgcF*#)nqr%_lV$(mxJE+LLj^x`;*$Gq-mb)4Us4 zUtebpm+Hh2;H1I~gvtHU1K*ixF%!GTt(eFobKDJ-@G z)gaxmL-fYj;ias#sM{-@9)iK=-ip4|5#0USx-6@PC(Y@hNmTj$)>3j?&jw@x2?L6w z=ml zoHHp4=sBsna~W}1^a`S3V^U*zXe1Sok#w04MAVC`Uc@I8;H5JTe@%C?0U^*4$7R`< zp)xiJjRy4#9NQd)!wrg}DfYlwKmJPBS-%MpEghI?Mf=G>cA1MYfpH)Fh6yXe_4BCn= zkU96nouXIrxaEs|&H@UXo5hJ{nR}blTQGIo!#G|Wti+ehA;$5=jD0dQC8{x6O66}L zmEBK}su@3;W&LFG{iKalT?XRbM+Fi_ZFJ5${W^c_V-+y6StjK@iAMT@q5Wj|E1scnWFg1HHn z7wWs9JM#OkJLH+{B7H}-S*mjk)NN+R7IIy$VzV;q^OQwmoKw~+r*j?ZfvDj!YX!Wu z7O0)8Dr>-Cw&Ic|7gRC730{%0V`UCosz7*4$aLj+Vu5YyIIi(Z-=OcM&1Ao545w^u>w5}E)J87A9q4%1Q;eKNzo*sb ziMrzrC{AQDcL5fd@cd;0FMr1jcDR5h2EB->jC`;$PW_HWFrCKsc#(C!2!x@b>MugzDJUHP^GIgB9ta11)1i!48-PyK%OA z;z!8UrkkI~2eDxn*NR&&x~uoH?K`S(vB^1g4ZOoG5KM(eshhQlSOA0xJ||O+S!|#_ z*6m?`_I|E8CS;&1CW+0lVxgEa4|8U^Ric&1e9WXMz$T4(f9WDKJ~A_p zs7OTUw)bsp3x?JqpuGl&PcfqF;C{!a%K09QnfbIro{@J<=i9{wt7^1Jn_?SNmSx9#DAgY=QK;cPZgMaMw~62Iy0S$cPrjtwJeavv*U1y7 zPHw0Ruh)3Rwvb+5I!=5wVtq(k2u24Bt?OlewdSxk6<%EK6(&WgtImk_Gsm_E3#PM3 zb9Y8Ic9b@Z(55b+y==u7#j)3Z4@YtQ0h3vtH6-ElCQkfn0#Er_yM)>--UJn+J{2mw z8{#=-R*8UB>9>@#4&(BDM;_iM3L@3w?N|3Jm!CGmK8-SIyL}30QEAV7wAWc`Tr$n| zX*jUhxZV2-{-Ffy*?)miar}c>&Hpt<#qk}F`sWU_z!j$N7!}7)T#Dl-E(LVE`O*Fp zmje96rGQ}4_jbTf{0g|D_v82{eg(8-{c-&Be1MV=9-^{>(R;NHi9#&2^A~p^n1MZu=-F5~85voKzU}AE^1b!12xMkyW6H(Az+hqb z(v-o`#n#r;k-^Q*(VD@~#l+ItiO$ZG&iEUzVQ36Iu(WmlW)^4j-@oW+YH#Q0?8IQ_ zssG!b>XS3GFf!Az(sSxNn%bBeI+-%qxj5UqI5X%_SvWh}J8?0XTRK~~7||Qsy=0KL zH?`F=wYN95v9x8d10Hz(Jox)}Vfa^FpZ|oN5R(q|@5kx;#PlcQ_?K}4THVrf{KGgg z15*LhUmmBQBKg@l*sp2nHyM5x zSByY&!GEK;`r$h%`3o7({0HC3@3#qmHg?=MR%6=bvB z&K_y+76gXxoawnac2O4eD^?~gZ|{rtu1@pyWm*G>#j=O% zTRSn@pw58%+Z&Yu_mM4?0L7)tH1Pq|K~LM)BTl#T-Pof5m@)5lfFC{J5TI(gH%1!c zWpXEPTA9K#yQhPL9GA+sMd_PXqRRE|LF{B0d79)ML|n$TdCqQI^|+FZ^3<3Bnps4C zw_XuH=ItKDl;eYwUuZIxyAeTa&pt!%QXyAPd{UZ59<~yreA;BT9@~pUewSV%T!|YG z{I7cyWjM22aP55n50cUoHOd|;@QU=|Hv_W~w^m z`WR*p@vtD3Rlcb7D=xK~oei4kD&J7_+l3u1z}nXAkzQ3ABt0FxmSpseq%+$fTkm~Z z?j5WXS_DJXRP%pO=7b-i)7acje#<4CVwxD1+{c|n{s3k#F>3>sfr?c2!Gu?sjVyUy zfm`!=VAJ5GV2^Czhnfw{a~??9Epk!#g9KBHy&B>1ARc@qO#^>CvY;AE*m;5;$rlrH z4*u*iCx&O zK4E?h(GKKLFa(^?{OC5Fsz3a5x?3WpBY$X|lfpjJ$HS3fs<69i+7YGVoq+C2&Aqm`jG zcSCQE_x>Spj7qe*8;6CPM7sd7pLhrqoSTSq<8cgNPm!gFJ5s^5Wl-D1x%GlAjdG_U zkPEoGI*uJ@)@#bQMpfJR-9kp=mR+j4en30wMYm%~w&Nt3iReRABG(8*ebm13xevU&4Phg&py~7Y$^4bi-pIbr^$mWY} zRMd2S9X;#RwbvVj`yk4c+~Qdck5JM`DHrvwO4cLRwNYQ=9Y#vCnftcr^yL{_jH@Z0 zT0?WQQkT7{S547}Sb-vZh-F6JfejkpK}-9Ui1*9mAEqNb_Uf_>cm_l-xap6XO>A+_ zo_&z5ygVeb97~KVWOpgoYG=c8r82Z^EIMPifB54lE{U&XPhwsldyFc{xeOj#tOpr$Pg{K;^YBB5kxX`vzuvEz>KPJ z9r1=~wmnqalw|YUW_Z=yXJ#*3Laj7nh(5b(QF7rKneI13@(98dTqKfI%J8u?T+Zk1 z3FaV$InUk>eT*lc5g1Bj>&9gRway}*gFA85A!`^~K5#yHapXRqF(-KiEqDkER|Nv+ zQ9=H4qP(G(f#28tYuL@#+BY{Xb%jI1&myBkPer56__2EgY^_l&ypkoa2=AW)5srti z{ZEx|Bo6WxBLrF;EG@rOqcZZBiDdTJxv5jPebOaQbGeO^_bRMKR$K86A+K7C;OzIJ zU$9xe9{NlWY=*xvhhO=|g>7)*?GW2h=S!V&sf{si4fa)+4eM*)xdG!iD{0ajT?fw< zZp$whvFWQqrSmcC2M-3lCxN`Sdc@k&v+dJKa_svjK2+Q`>%&#V8Z*qv!HWdEtkg*B zx;k6aCQeGvvLNv=2XZOG4UyE)K{*skv_>XiYWHyA%KTWnHz>-2xv7r1Y(a0(UJwEF zl$qpt5qTVB4Qp!p@!?04~jCh5y_G`#809M4f>>%(*CH`>_3sSlKfBtCcqhP6vuBp%)C{Mqpk z2w71A=zA_I5rH6MgSv^}$Tk6BlAtjHzKw{rEAu?jNPVWR@#dsQlKEtEyBoD2#;ysL zlC6yv4u_G`X>&j6K9un#!9>ax{&U+YmCxM4xD49QIOI3!5563_y1bJnI?EoD%U@c7 z#8Kb9p*%br_d>RxXNd&~^mwPuqyt%V&+@{cl_0xsvYkg$&B%}ZGi0u8Qt9W#kc1fc zT8?ZLby40pz>4t-$#L_M+=puI_uTS>7jX&d?>Xep<|)aFB#+|T6PnU=d2JT}!-Te< zPSx6$jo=(2-)xGllVsq=8{h zN;*Rm!7vua(>7&to6THjs9@2>6UipmIk@xkJG9}5EV0Z1N)fDwoAHoaZq>9IK~?;SQ{3~YOk z9(4;BN2sgSZY&UCoez`3ANSWmm^6>T`dZ)J!C4S}g@i-ed=o4TGLBdaQbKKkOFtCC zV>&W1rX7|8t;hwewix3yG*0Z#@@&o#UZO)=m?A5>*{AL@_f+gB>M2j<=iIE&p|LI| zb)5t=D3x%u=}^pa1C|$=-n$Bdc6uS5v$3aXTHse2rN(`2FpiSgqa*(Ka5so)cD+o} zarZ6+mSzxtYWYj#byE9Y%%=KU_ZnBGLd|1wgBN3y-PG%OJ3et3BRyz%zK&Pg>Adr= zOi^|Ryf(Delb3kyXjg5$_1vp>HS!4@rE6q@eXmv{RnxJCYwNj>EBY;)$4F^APq=Q5 zJ=r(ov97~}oS$3|3z`S3v2PH>hq&j>Q8N@u>`h3Tv^=Xw!?_RNt?4pwgIp$0u^$g< zedu10qk<^&gw!Wcnjpzb45f7LTZF`-qGGwA!+Y5#i|U)l3$XT%)aoH7&I&ZP7!a~X z3h9R$Wv0U?g7X20Vat)ACLZtF@2z(9$a{9-7^XWq7Q+={?@tsY{I}W zTD%or#$Vlehj32cUigviZRJ_^nHwDQiJ}H7M-{ z4cv&wJ00c?Y$Kv+bB|9!UhlT>gdI-}EZ7-?3f{Wi(zZFVr(Knnzikb2CC{yb_|To{ zu*dp5+ZeZfL9jGpU1T6`^_aQPtSg6bfV&Nk0DJLRQ>chTy7_7sbk$p0>DZU*OVa9# zorKln%1}A5Q6vonvV(}c?EGLjyA=C_QB?XuEcB3K%%HE4%?ZQ_}9bZ$P-65CLYOh&&Xah%ZuS#cV)u)AgL)(M&#ow9F*x%um$i z*o}dZ3Gwe>J3W~)gIMY;F$uTv=()jJ28~}(G(6|GyUK|2>DhnjowMKs-Z`Me5aT*A zG+sNk6dX2#%N#YS?UO)H#qC+au$pvYz}0cClRIh)ZE>Rpo3hH)RRJ#PIXX+`)T3SW zqDT8>&*f*6wj`w2=gwIHbgUA&=W4K6t6ctG(Wu)ZJlZpt9V|YQ#a>5Cc3p^fkJPIz zImK%iU!aFnZpOMr^d`BXNmsVAJNxQhE8garb$TqEEy3r0f_=&K=v{+5Dq(}Kz0lw@ z!`-Y;loTyh(U4m4`J&-%Q<@QfyCvn-dwe~|!CoeBC;Vce*JsVf6lwj`VLQ)j zrZwXTL0}D@P@izsKag#%IL(bU$hnQd_Gv%FTLwDrR#EPJ$q6TG#;D)Kc!3W~66U+3 ziSz7CDK3T59x{&aiAG**2haHt`#ip^>I9}5vg4e&7?*H(&~@Hoh5lO0&=FoZq>KM$DJ zF_QYFDbnC1Opi{!&*kml22)r~!*X)-g4jG_#vI%zD}-aduskPPN%{DiuvseEq6msPuu5q6g)_X z%A2mSXs0X5auP|rJ^Mp=x@oMcuNzrMD%@i?_`sNXpm!;ZyXAGSnf>UBW^1(q5Ckx^Q_lPogc>D0IgPKRgpOe9j(8#( z=~&{P0dk~t$-YZ8GtHaAZ;Yo2=35D^X^)?FsX9;W_%PCA(%N7yR zX+;vUB4N-l`sfG0O#*KJup-hJd>xrmW0SBf;t4wOphzU~Qpd=kbq)%!lpq93!ak{# zOwI)IR3yg$Yt4z!Wutx2fw_QiWHJS7GDKfn$y5ppoD{5Hdn2^sXzh&Xvk%8u=?pq8sOTcv1iIiZbF!3;t~PR7t@Li3rzCR80amHBJ-25C2G z!b60go)=_#J7w<69*JsKqRx)Kbj_S1ZR&9r zqaRUh?jT;9B7d@gB7L zMOFYrYU1|NU4l`RW<2+nRCspfgs25E^=M1HeH>U}0hT#4Q<=n?G2 z3z(2n%!HLa8)DaQbzp(fV_SC+#og#ZQwPu6_zFo@%(a$-$#tS_Jyjv{30&4ZJvB?! z1#Wr1UqdX))^a|*Og979yHHLdlu|Y`D>~B*Qcp!rIq3M7o$Y;zopLX4PBe{qdK#Wo zk1_?+c(xRGsz`Wo$WrC_RDorlF->6o2DtNh&bYxL#Tc>0i-bke@k@5^m6CQG{0LhR$X$pC{ek-d*QNn{wdU47w z@e#MPDHhXqH4{AaG=H^nLAZqAkA4y89aL6=lnRVZAJD$o#b{3yd6aaC3Ogm~?iW!F zQ=qgO*xPhRp(#sQ)XS^O$SA4@T zq@&8{!U?iLE~nEHs)wb?qbX7>QdW>}>jPwsc|QXXH-)&prb_#qL!cDV0UdUiy z1tyMZcp`HBEp|$q6x(-g%|LNdmi1EU%5 zW^JdF6yOgn*L(+*RDHBhVhpivKcu&@#v?03&$~X57uJ1HNK|4b4)LCD2rP_U+KY_z zOa*m7d0%W&IT*uxYs^g0ClHCsPdbUE{(+|NREf!Wai=1NaKJ}|Ye(~mKWH%@l}%1x zvU!3KoDNnaK3O12F(`wmu6JJ^U&8#A0zrtRt$HvETX3Z_5=W`w+J}x^s&@%kwah`e z*1a~QcBWx=#)G!8hdEVk7~8QOOVE(z_&1-_((uCcU+%8d#vm8fM!eB7^n||vy5qTg zS^wzfcLy{m@P?PGcR{{YY*Ti@JzKK!)towCQOz{}x+Y}lT{1~_L7n>~dg8v@+OOtK z(%yj_VShdI+KwTJ{(-;#gZ^&Y#{EQG*u$1=k5=@&2%$_kYcG zeqTrUZ|w0nfAX2Y{ph}Pmp~rr$M2tfCeWhh$MH`-6X=2Tf3EYD0`!NgS58e|9 z2>m?%aXuEtALnCX{Bb^@$<)u+zn|~_3E%m>OMh}zl!=Lxo(V`~0rysA2mEa>T;See z>_9s@PDY^TA3Jc<_aFOs|65Wl%*?-E6a7BS|B5z1H>aQbEB~U+H*cf=?HhIfbHe8z zwD}7t2J<&K1sL3{fM4T=g$1~p&dLr9oqzkd`2(f`WP|^Znf^JZ@;hyQi<@7y`8SW7 zKWg(AD2%`RTz+$s1F*BRGk@bT*yuUg7@3(_iGZ*HF!OwC{r5;Wf54lVIq76r{;+K| z=U>1uewBv}$ayg`16ge*PM|!T0HFC5P#)Hwt^Yal{1pxZXjusW0GOD7JPI@C-}qr> z;P&U709IBYKm2Xe%YP?2?!UH^`@@v=7sw8#Uj+iP)|^A@q+D{e@ck@6Tp_e}d{e_x>xD3bc&>AA88+Z&d2VIQ1%E7_T@++0PqpKN3Hk9C7qpvs)7V^L+ zfM6kr3Zu4&Jz+Lswrn_K#nO}OVFaeBcXYWk-2UcG zTfQdJLfaaPDL+qrn{=XE;- z-I_kw`FPXY>2q&T;*Z;?5J`7Exmfouz9KGe&DZyKX#DA+RsUggNj$aj{PyGq+3&H8 z>8Y1v?jiZfcFgov+1IM_@k(~(>yWn{{nORKrs|x}-7Y^t=i_Yecqe&en*w6eQXS2O*#5XIBgFgK(JVWM ztgDsg<|+N@IB>#yhm9~_J$`YTERBjSWqvucWK9j+J#RcIA8eP?87CF!Y7TGyu}62! znw{{eldL_OcA6}H6RJI*!xowJ6M$TLYUYd7s*mgY@fpW8bQhuifUI)|m6Y6`#gP}@ zT(!EXEy~Fk$_Hic_=A$sj0GQDa%-o<&kqcObHy___>XBXMM?R)-&$tfqeSN#b7yVj zo$f@#PhxHLr`Qj?tWLw7wu+b%riqQ8Nx_`BoLG$0cqDR|8Y84{6dX&> zVf8@F|LRV(!j8-4lp9c2Sap}2@AvSq-o92RE!RB`p{&1djX>aVHl4C5U>P2>XR#tx z{pAxUj?~~vH|LR4?6Y8tR23X=+v?J12vhu=|M*>3p#OwZGBM$lNY`9htx}m2UWkK0h&4`R;a+-@}ArJBbYMw)=%Fb7U zuV2b$2lFIU%nK~ulcU`@*hZz$M0*e1Aa@q=n_W_*^pN<#Eszz5ilCgB+Lr1>*FGk# zecj#be7Iy7hYrP<$4jkeXqZRi#30oA6hd5P+OrRBX7=_NhxhXM)fc>bAtdPhiE@r> z2Imp;>?!C2Rc&##BDAf#>%I9CS7z>B>7xc7XB^E?+GD6>G_k$XP}cn-bLbXsyvK?` zcXN5IZcj@n+?mZy;wqfviahmtY9;z2D{7U*wXBO(wZmDw5QP_5HJN~l zs)DETK%_eATm<%~m_su33Z~s!tWAe`vZB{jf7k{|(si+$%gckL>7jSCP-Fh+KoKot zEoeiGpg*ze)>(Kzo)nqPg$HIdUbjww z6xpEOL0c2V+LtLX2B-?=dXNLE?_>T)ESdGS5r#&ERWMd(t= z$HI?{A(I3$hVmF{*5N5cr%@~KL-2J`G2k?#0mZdFsn=ABJa5m=gd-~ZB*x<(Q}#p8wl zl?ajYUd?Mlu#K75A9YatDB4idM<>fKhfuUXfRAd^0RwUhfuM`m!LsR4jK{X9;ZiW4 zGKFsw<_i1@_5?I*fWF0$s+b9?D?r>|B!vF4+13!>XuN(P^_mFf+t)KDC5_Zf^=uJm zD)QW0v$YW+B-C^^kzKK#b@y_JjJ z>u4I1w?$Zq7ssKXK|`WkeXUQVDzn-w_qJ@e;MJux>x}tc)=kgG6-l&@*m3MrO8KP*uUOFDwUvhlKEeG28Bf$JEZjXhVQD+$`{s*Oye?7;aTk#WzeH zY)X&Z+GQ}2$*##SUnRG~(_bVCoFuw^S$0@9be2$Fjt)grs)QX*x-I}sl!yUG4IF?s zJ?c_e8|QmS#qpYC(Z z)lD|&N@@7_WiMBe%W~Hv%fVuWxe!NZvkN2%&PWKVCL}{ztFE}2lCgWENoV90WK|*O zRaEV_QAiZ?FfHG#{}A@axLcRe=y;l!17W_0ey`52@G94RQ}YU{Epbfq%Ck1+udAW` zy4h4Q@Wh=D-9|Z8M+FB+`VQnioGH#Ol3XR1t8tv|Dewyd-=U+Z8V~>$$pa$FDXQ9! z3H-5tM!~mubM;n5wYrT#RTahcxa?4-{!BcB*9TvfF2u)MP8G6~NtKuBi>{KY%!bCa z*c^1GGu)sSm4Y-9#)Ss;$4dcqGFo&cYzG;`KJp@kd=tXMFzV>f25_Vf=y(gSB}CBc zfv^2tCUs@ieO|hR10^GSx4d#_cGR~Yu9`k>IZpr{y!>yTuOD7E6#>a_$1 z72k$KeOmq9RmT96Qvd3eZ9AT&BKW2V(?M|)+2IuY zW-@yw9XPq{7H5Wuw-66*x_FU2T&|$LpwX36B+4OWX?~4AsSl)v1@U{~iT5^S{=eoC z^(pn{x~X=D;hCA6+#0T)4#0?|Y?UN$)m(Ds=d0@q3mceMxRz5I;c(q{g2u$G@-lwF z|NdZ$bKR-b%k6Z5w<9K?tCh)Iznn#}D-RdX5ygaRA<@c<9}YLB0VWAdspJmH1fzeFR*HjTqjv=EjI;GF8sv%?%T7lu=<=E}Zq~BoK|VY}n9{ z8fX2CMD-Gnbg%I3=_`2^Vyjs51v)CraLXx%oLy_lMz_8bP(RygKV4ZS=)Nz4Ms?ui zb-QDeaB+8_CHEynF5q$^)*oJiMsSV;1Ro)0lU3|xB_YK-h)^+Fu9TC}k3HsY>j=mr zOFlpP(2<8oQ-6>!x*%T-Ni-YIW>8joZ5sHs&D@%m>3ZmiL2+7?X=`3t2E$P6QeEN0 zdw8?zk~9&mIUCQxnl6d#V8&VjU;PxsxA>c}YgMxW#cX+alP`p!*G0;9zI68VW-QaA zlCIQ^Mx0CYf?#w*;K5RK2`vlY1lLG=7Q+eGZ^@ep#nu1F(>!KrzJkz(FEr!V$ST=1a34!Dk+ywVid}G zfP%5O8Oua@u9iTJy!bZ%ifz@~VTyQ|2$N)Lwa|xSIOT2Ft`S_Ci2RX^JFL$E($2gesk<8cWZp|7@9clYH zK-Im`?6C*SY8$-=I11{|+X(E3(d&CT7T^z}?Zos=$TRmTOE)w9X**y6iO>naBH;CA zra>I=hgS++{^b5%s{=N5HPuc`Z}lcnKqwLHYpifQ7qsGnq>vj4p1}3 zOD90*QiVmM*?6d(GvftE#C_)VA>Rt7CFSfgiyUrcl*2I8_budHL-1bFzLnq@B}N&k zrbMB+r7NWfEn&ZWRFJJp6N+z`v4oFt->AewdTLx)Ot_yIPGv^FnbrcQKUW}fG1Ji*rznd~+AjG1K_zdoNm?Hm z+jn}RYz!rL)&!P%2_77IY1G5qAcgjU){)czq!sGXl65#b#uW(roHJqN6=9 znV&*d5M=@tkA!`rz!4v2AavSdq4%~~M1S2BpdfQG*-=tcl;%i|sGi~puQ&hYGrF?) z#~mgb={xTo&q9+;%(*EKo5zr~Ks_UvP|_OAQvn9yophNojO@C+iTA=}Qj|7SIl8af z;aa5))CL>-lV{shokYLAY0R+NJLw&q90;SpK6hGVN{`GV;2Gw z^H~)+7;x&(8lOiE_#UZM!L;yeU8a7i(5YNq^!&{{L)C0pEYWgne)!YTNGWKB0?pd= zls%;lXU?1`ZyV$I7Ru|f3DC=5gbqgf_Xd%|n1u*ok`m0~$#&B)LCTSU5z2IgprN}t&;ZgOg^w7B&mn#J=*eMP~K;E z-|2VFTDf!?Dl+sxEni6IDYDCeWa-dsh4q{)`yh~+fw#ue17}kNG<%aY5O^nW4;b9S z>ZqLvx=6#wjV{K1@%x;P6vN?HZn{;~q{lnZsrq`z=QN%}v=nn*j^S$EcCA{EGut=K zTDnDVcxd_{1_mPox3)+lj6;OLz^hR;HfZw%NVZp}9&sVDq>TR5)-sU1gPh*$u#HeQ*N8^vb0S2E<;;|4^1EM`J0K+!8 zF6F*l;8oSZ<7^^vycOlC=Is{9PkKow$PayQlFy6unH(|^8ek6*U#hSy|J=TIPjl;U zljGY4RQh&?szQgI_w*)b@oG6%PjFi4!u~$Vu~Sm{RCOFUZ4MAR?a0u0dZcD{yQeyE zAqStsp+6p~ZJ3^-hoTl7KZCmy{m6=Z5&_lZuiwDjgP9Q}7|8?S;HMYB`{Jd5I}TD$ z-#5V$)p}mJ`49pH`{aJ*5Y6#&e5@uvAzh#0v<(^hq4BI&Ue-JAtXFjyDl$${_F}l_E~2S_r)}9M0!Wt2+m^5Cvct={a%$5)S)G7&*jQngLf?+8 zf;YHO7txvHBxCwtIeoBl>TUR8?@T|Aqn->AG`U~}rW&ftY(N9EWAho?I*J-0wYO#* zYQOURQ%8o*_M+5~P~{Y#p7r@SLylq07r_5ku1izz4BsnB zVHny8Q4bNc>UkRB(s#Wd5E0h1+1VtWPcje z4>uOUAM4VdkYTn_q7-ETRc8fG%pLG9va8tzZ%CjVGB*-9H)r(B8TzE*Q>U>u{b@2_ zoAcBC!OcM;;6^13Avut+^1(YQ#UnP$eEjsKSvIEbr#={6-<0_QST9vB)hA>e?}k!y z;wC<9J{*TROk?@a?uz*L%F*|S(4{(|n|&me(;0eyZ{LMasR&ORFX7h2(k#LYiZKL% zCkZTdR)M7s=E6~+ZV&lB7(=UITC>I4xO$>Y^QY=ew1Znuj{#HvxRJ55$Ko22EOG_H zdc6=~q8GP~nP}Ns_XHf2O7EU47Xcz0HL}~7v{z5b7yaEoct7Wu!03bfKjggyR8`#; zHmryspa@9kk&=eP2^u7%1nCZ`BO%=lf`rnFgrtHrA}vxCN5Ck))-|?P`po1{VAvq0B@yUUDUV1TLh$Z zFY;-yF$U{b4mdl|&hQL-2TM?dBkXL?*)&$4^q+-vSlhmR(@Gr7KFZUJ;dcC1Ff2}SfUH!i|X?-^+x|2RhjNmJuV|e+IGzvbt-t_S@U1y z-J|2WSErSLkY$%pcS)fxN-kI;0Ar%eFX(1&=QlGlnPQ*a7O4D?+=FBzelRMmb}%SP zgvh=Dmkn(jYV7LkQHj@FyR~VD7PG?y|EL zWhWiV<^@hG%pT)iQW+8)GNHhC3Fnz2%}PqR!b~_hL8pK7q&Rkg!!gci%^uvgtjlVZ zSs_A1Dc3udQ`>1y!=jNj}^wQQxT{UKk zHOYyKnG)SN&cSGPHg%W4gyT`wO`o4$G9Lu#cw+H8xp~k`XT>f7A0QxmwRxEU{3aHd zsFVge5Mhzn$>{|YsEXaV<&;H}!O`!ZJ$+_1Y|w`8^E#}0E=yXK$%Jz(uI8JwRH#B| z{Q29`w5b9$LaZYH7O>Y~xJbkZ&nO)8z?aK;2!Fr$hL_;dTRb=@_bwdIA1 zG0BP;uJk~D2<;|PQmmqELbN}+mKwD&tx;#uuFh2tG znndl2iR8BD(6%ey$n#4_iMufu@lJZsoJP}$O!6BA$$6H{O|kYd>$<)E@(D2A5tdvQ zrL|<-Y@RTs{GkRHe=g7#do9IvrKzD0F8&6yg{@5)67ttJ{S0TKCprKq1VBOS-Smsy}!5Ki@x zDwt(sO_RTt6cQa}5|B8K0F(5CJAgDQxQbD`OFf`|d`4 zB*7N1AE-xoZGjcYatN=ex^Kvdn9b#@J62F?YNyofX4%K+%pTY3aX7M-m=l7jj;PL- z3=-bnj3KAmTpZA`aGV(c+2p*vm!CeYoMv2!R|EXmIp0ks442*2`(jvlek}5{e7+~} zx!TeP_$*}L1$+ii357jT-*vUE(i6)lj1uwxwE1FPGnlD|0e#_viXcH+QB2CQB-Ik{ zweg6!BB~<$TI+$p)@WBW$#>)*aO9R(V4bFrMz-5#qY;5ku4Jz}TRh=W(jp2O6jh(H z{F-=72WBt#X)BTUE(gN4Uam+a-f7EuqfSlI%Frixx~y7$rwsC)siA=c@77B|}E^i+9IHGyQcaeulCe#3~fTnor(O{VRo}q7quUJ(4x)l&#gz$#qR9jvE{xnVjs3%g0?7O*KCjR z@;(D+w# zp7^LZ#uA_!^u(L`3}&en7AzLKocA(b<&uYdn$rF9;-@r0qb`d&q(ON`9!i53W5nZl z7F*cEuVmZOFR;}$pU+t4xhO9=6;w6D$euW3a-9=48M;f7+2!gAa*funRIF>WtH!&@vQ|R(Y2!{W9N<^v*FWxOtpDd>3sNv zz5%-{+j!XB2J;&hy2n2)3~WXh4jWKrL<)BDf$Pm46lC(Nq--5%fy$t>g^1v zlqPV%6~21WLpzh`XV1?DuGpp1#|Ss$-`C3(_~6EF7)m$pdh$qh=d&np(do+-j3UiZ z1P%(Ly&0i_!r{veYVw?=cGq7QsBmR9TB!gv6kYk$d5h#CdS+otZdXIxo_k4MC7JyE zZZ{idY7?vdQVx4Z`RFRb>dkC(G2%)g?9^p$iuCq7*04)qZe#D>=bLLLJ-!?GB{bJu z(j5A%q?kueK52eAFxxFWuk_5lZnkmPwc=Rq;`ynU>#zrX^f3ECrxI{|H~qG)+S`ly zGM{MSy4g$(@<#HeVQIJTzY=^%JI7rfrf)$Rp`R10&Dr&ksbeX>=q-Ksyt?~RY(IC! za#nmvu22?D(^~;0FRQf}qsokko{ZyC({a-3@kxXlw~DrI>8y6Sv$Ldk$8X+KX&dgd zQ7SC;n10-!?bL_sJr%xqe1n6Zui#a#9-ljBd-{vdS5>(;INOC^pXpX*T@9t^#gGN6bX|`T954CyF zH8ss5TrfsD8lC)FexcDkk`z%*SAL%LEx6ot25qy@D$gKVY^HXeh^hs)khQ@VXF)v~ykZ-5DGo+b{_ zqPXECHXwag#BD(F?u`N7#1~e?u_;g4XEKdnLsmZL6jZKGTE{Nul_Jb7_y(~B%a%B^ zmkl$bqF-H?Gf%m`oUe0Ye9c_FOZIinm~|v))B5v*mX9qJya(Obtuyd5+0M*GF5 z3}1wqOx6v5(WzM3v02R@3{ft6KRJCpWC>h)_L_~fyHs1XqyYWxW2-y)=N-F!m$Z5K z!c7CtS&z6x!1P7~joCfgiswc3Cj}s%9KHD6B3(wYhH(^TF6FwvOsm4VgPHtkbPA(u z+SH9Cx-&CH=tbpDUv{RBajbcXk^9B%h>Jri^QA$VK5Ji6ytgT2?^efF89xzC@aEEA zc{p`~W&?`88Fe|KeLW-Ai;B~^xhi$VZ_WP&zWsyR`BM(E;vUjh7geZwn$NC|XPG_+ z54U`=Qowjjohb=*^X`OYNS90znpbJ!jwdcL6J5l-xZ8i)^mMq-W^Fx7c-GIg6A-SS z(ggq8+KIj0?%&r=0O_f~?!GdzY3u&~`?U|?{n`g0O>^((`?U|i$=ZA0_i8C1;JsQ3 z2zbAif_wjdKnp6=?{V+n4>&P+@B9A!fRy3A@B8-yx;gKC-@hOC{{0~P_k--;53+wh z$o~Bx`}c$F-w(2XKj4U2;C}x%YBTmA`wvrKz(B4dH=GL$^ZanAq7wa2x>f(s9CD9Xe}WbO++MZDVYHB`<^Su|8v7}Ee}>jy z$zMFgE#P2f_)pw|0eyeD{?Xj}E9s1f(Bk3&8bp+|R56{FyHF>`-aG;X|L%(mp4OF%K8K=NN>*#%bbr>bc z{?&gPN{13ORo!e6AkN>{=^fHjKx^%NYX{6c!0>^2xqym4DA0C$Pka5{QTo1OZ_nZW z>-q@_=jDJN*uFz3@$6syhoOWDNB#gM$bof3HPYqb;pPL*5P<@P*8lUq`hTLAV9@W& zLQuilpP&SkTmbYuiLsmLg~+Zb0`=1t8Wg20G0Y&0FOWrUf}4W|8?K| zKS2rpgWrS-^#3}SAbiLs?t4D@VU!L$^}o4Z`U#~!^Ti=>;B2dXUz``&-vI*DI)Wg` zGVFf>mw0~gmr#pDf50W6n0UX_1Nab1u!B1Ozd4tFLg~+ZZwPWN<)^p~0tURwe*~9) zsGdbFF#Z9TxOu+%-rrX3AV33=J&*kF&ZQqw`ZM2~8@YC}&!unLn;STo;~(LB^L>9_ z8U(dC{nxp~4FqoozV{)Nc)|Y+-}^_DP)qlJfD&>AO9@ z1mpSUdw=yRxq(%=e}eD*GfIEvdn3Ejd|em+8trm(AzK{%kMFr0^1c7s(Pco#Ls*xa<%<7!25$1OqEneqLa%bMY@k!Cy zs3n+Dmwm}hN#o78HEU2tIgpwAW@J4D=2Q%hjtg&ze%VK9#kb?p`;x8gho#&)u z2j^d<$DI|V-dXM&^?8nAW5gV8InQizJ4?~x(Q;Vr?w9$dq<1eC3U)Uo1`6-8^O=eX z2Ud~YHoDYYySscnpfK>|om*CKhIi)sMlp*To~hmv5vzNTm(M-!GKcH@tYhO*fU;$_ z)YaJ-zwFN8%FDQyw?>-_YBv`mq$tW7ciWm>XmEGeAAom;;^wdIP=|uob9eb`Hn&F; zTqvgq%gL2XcQiXDEo9%Sr0TIJ6f{Mjm>;jBC?>mlEI``8W@ge0b17zqOq1t>1^d*R z?U7z>g;D)e$EeHA`d9A>Ts;#eCSC_WPxFT8DKnOGYMGa6Snovk6z;N z{)mmO@&FImXMXZOZ;Z1iU4@0w1do%>`h6<0sQY8;VgD_Y8gpM;~ zv#)C^HFG@w6L(c6JPKPAczv7GM+HAe@TTbC|0}tM~2RI);$s zlQ-E$ExY09p=s)rCkF4{StAS`s9IuRXk@+?I-K(wRj7~ooVk z>S>$gtsDm0Woe1KQ&=ll8>w6Pi7`+bp1a_Lhj^4-fy-HM5H#iNkJpy67Tyc3FhxC~ zob$TMD4XV#)s_xXfvwCE%iCV_EMYwNA?5v@N{Yekr#J#!ES1pKD{Lo3i95K6dn-t} zUTJ-%oqxD8o=?^HN^r+kXigQ);&t*!5|!?gtjorIM!4ZOI~(=0EpBWYKgqZ=gy6sN z{Os8+Y1?<6aA;YufC5@7F4Pj7m}XuK8O2kOB&G?d3}al1LA;@pDUbIsO7_*x$9~wE z^AsfaKmh$z>&WpC)(C8UZ*fzC`)zhL%7yh&H@e>>QYCE;iWTN;x!>{(lNOB$s5oC& zzf609ob}Ynb$zE~>@93R!rKdt0}7In8)DogRvQ7iZ7 zP<)g%3P5wims(`;EX4949J}ZBTz?s}Z`vXC!AngI{M9}syVP8%0JLlPQb4(hTZE8o zI!ChyNst=P^c(W$k(6R?5P~$EP3h1^C&NVd8 z4m(aKZ{ak|hQSISQ>i(4A8SZIh)70Rf9*T*it={yy6NkipP)%mkd;^`;eQ@V!Z3o25_ z^S`-Mhkg7L+QY2e`3npm@ij45m_PZ6+Eo$J#_O&${yvbx8(75&1_fu~NncdXGZ$h#CP?sYV3Gf@E;wRp)<4D% zJ~pVsJ0(8&mR=Yx{XmL_SfEZ=^iD6j?hW~;O61ZJ*riM+$4PvsVKr6F)C|h8<6il_ z*TrpE;7Q}#BbSB1o0xmXg9#T*S%{5@FEs-t!U*GrV6O~P1% zZ%+ZG`RqE6OwG6w;>m(|oo=UFJw5Y4N&)gQs)p6tUCA@X&1dI?D#A1ntMoF}R@ zSUBFq$cvjKgG5%g5KF3NTls-e2-!+WubjV_OOo?#eLKYkSflB3l@^4f+E|@!3)Xlp zBg1*Sqhk3I&TV$#uDooyu(yqPVjOo{@A2!;g_H(kwk8;0KH(-;O6MMvMg(wL7)I2K zm7LBF-2vTU4uZ?l64(ZN)Pz%GBK6fHGP`uh*oe^biKr)}b6#U-Dl5*WsRg@$H+asZ z#Bo((t+0$i;+eBb)(CY&6zc4{E_o)5^2zG!J%0Gv{@U&HjjTyYN%|TtO-8TeH_^Ms zRBYLWk4t5Pgjh;a9}($py&Y3I0JU^2THJr`Swp96I`@?JQ>q9$drm*YktPxb;U+u06oRz2s2X+8)~Lax*TTaR9y#b9?hpI~ z>iREZ1O`NOCwT_hYLoPW&l2yDKRHvh);OzR+HqTQKq|$uiw(DAB%Rc6(v~TDhS{`$ zJ8F5Dxb3_K3o9Y-$;V@l>Pa$FrBa8BE`dosl}@g7S;rG!ZZ&!;#HzvbrYlA4TB9#3 zF{|e~u8>$FN3(n8*eimG{E zPt?;}jcH!r`t-yF|J6300<;2k>756})Uf(G4)Slah^q&5`J_gz zeHyb#A6V7VU9i;E3!+ZbYr$N>%7JB$$U0!3TvXmTrWh*z601g##g*@XmoKrThLjyX zp?mCHd4;+5pl(e~tRW7(J`O#HkklpVKYJG4NAIQErK<`;ON=RvNv#M@ik+L-bkJYoxD4hsiIUDkp#svK7Qk{~aY(y|^6uuPWS6#ZP z{SGTga>on7C^jhO^4Y{ez<-O2^u_xW{YS41+h-U%LST$d=D7^2G*C_g84>~w4!)Nm z(d-usHM>UAXSB+k91($H*GPitIPqfHny4Al-U?3~-|(*rj+xBL>!~+0e;0a6ry46T z6pwKI$j3#kjcc9Nq~m(Jz8og;q0rh7y3+&iV1d*#Y4rsyvLYsi*N2C_^CVQ=N<;Wx z%QiMryz8;PxIsGE5~Oc;yoW%^mf`bQOamXbh`zX>z~CbKU`M-m8GF2cuyUb-B0K(Z z4FV;DNd0yiKipSGL@(8!K8~*+o<^+)enL5QmEk_6o63zWf|;8a5OVLWcigwf>1pK) zCfm!>M+(^R6$W?c8EA_%;X9EHk7by6t(jzzJPhTv*BlK|=}mj1kSC6j#`)ZU@Ty8Zi<5 zF;#xL1x4)fOVQ#`H$r~31tGnnEczlu@!38CJQu;6=BZ8&D<|3K1t5)A3Dq*^tNQGY zkuGbtY3nx$9{rM$KH{#TY}<+1eou_fvh;}lh^bd_$Wm__`X~F6f}!Z^7{mI)IiyR7 zh=`#(TkI2QvW!;maVCr(RhfFt;u?>fE7R>YMAvPRdTMy%{i!w8S4wLz^0BRBp*RAe z*E+^6gTV6zEU%nNkE$)=+eSwm31Rc!IYKzDDD1}x*#B_A{v)TkvT%J=d2|GSopou0 z^tgg3|F9wYmec$3?17Z~o~mqtRDw-Ly>rJX%X~obMA&SSlv<&WA7OhCqTTm;ZnTW4 zb=DjGF8fH20rOJbrR z(8Fbs@iL=?f-3ax1QB-Cc}llyk4>0Yn8?Cb&T_t?nP}=?KjvsPENbI-mJa=b@R28; zG2S32&Sz^+s3dh6Z`eL0wpnC%CUsFBWgu8sHd<+xmAqqGnYEl}ahq)&SaYDyPDr%D{U zR`p`-Bki@=@hk;@L9Zp{^nyE~_7n09X+ZP0S>8YcbI(^Ult+CKEv{oL=a|W&nyxA+ z*paU69tnC$1DFi7AbcrYR!=(sqKz9)&kdH3lZB4S+o~G0Bh{O%E?Njtji&~hQ`3}v zUO`NV{YQBhN*C_+Q_hqHpq{HUyvkMY&lb)~a^0oBC6&17C&`>nXd#w3NAd!Z>Lj#H z_U1%ws$}9M2j8}+U_rBpctmzy;;~J1HIH!LTp_8aN@oF+9QJ4(&9!9h1l=35Hjf!4 zS|`4tp3i(n{x+OUYN6Z7nN8lLmHP0OQ;@1I2%uGuUYOa^CXTG6zV#d zzP|9bBVNYrb=SDv+ET60((Ih~@Waou1 zJR&=7wcb94xD0b%pY%#-B!*i~t7#J~4hQX2Yf74Y4jNx7Y^HM;+`YT5n(`DO-TmQt z22}mtg??TVm&!M{M)h9^L7ZA2n6GekDE2M#BEspng>*SZ-}XO!0kSTsobu9Xvp5=e zoGITr`DrY+qNU4aTT4=7&mOJzqQq%CVFzz6gGXh@9ma5*?de@9PgYSVShpUlrLd$* zDfN6V=jryf|i%2hMR5NpJnPnzOd#bw&@w#M6SZ=sGPkcYG!;)_6;$_W2`LzN^;^P&tW+<=K0XNC`c$dqEX20V&fdQ&kyW}i>^QX}DgD(0hEBaOm>bZcF|b9tn- znHSfPe`#}Do7IxPhrCQnpmDa2K;KEvK({`zZL7ewE$1qX5TR!c((v{hl0M~uDVHa4 zM#9N8&pmON;h^EuXMxv3hagv;pQw?9>YvBBBm5~pOaG{(dl#jTg3qqkiDsXxA6^&i zR__eM@^|b(b&tb}sfSiy+C{r*zbCOu&kwa{P-{=#Xu6{cA5P}3`>;S!+reaALqdZ) zB(-7DY@G4z%1qW(e5gPZ(?%Uy30v8Rts$T2(>?%;d?{mzJ z%nEDX*(MBh%kI0}%fa$w<|8Ycx0D@!FUz1U{|aXWZe8>h^5Lor>#9JR-&CnH)0{6O z8*vY|8}VJI?V}LK6G`oFCK~cfjB34}o=&83cBH4RC7cG3;sk{lu=I-7pU8b_K00yEqphad8P8+rBvuVL=xT&2WHyO^TgTk> zCU_+75wl>y7sHUS&T2_^UU-ImK!Kr74I!~M&OMU#DT4|Uar0p|Da%L4g#siE%XVXx zDA0pTfT&=!DP4_Hot&&4yeRKYY3A*aHivFraAKUj^%@T@F?F+k-UEbv!6Txo7=~$b zcGWO#U81`S**M|aON`xh3TsGyqWFi~Q1oKX5UNhp)KZWyFxGc7@ zmzV@uK^o)rS{8Se>2&|HcG@YLNC6@Di~jJ67_EC<$uh4>rkZ3Dlqe)xpv8zR*bW?H zVxpWQGAn{t=JrKRvr>QVDu*Oupn%l)lR+z?td)Rt!*BwGUeed$Ze>{rv?A~VnQ*If z>jXf2`}qZPWyW&R8P|#Ig0~n66CBv`EQai7tKo6VYZkr_OS;k|=q@y09(|DBSn3^J zHJK;o+^wIzwb))0xjd#TEt$^_)Q=+4O==m>Se$D?Q@L-W5@KbYkpIx>dRX37Dzef- z``|P$D&`v=Dbpu_COJv5?ZW2M&zT~Qr}p&ox1Tm!VlAKez^}Zv5Pt0R?113ul`)G9 z;3xIN1;xf(H<~l}wFWB$1MdgYJLnXY)McH$81*3>&f%%vKc3QWyJDB!C8s>!0CnTI z8e+})Ix4;k4)uIa87V9E1jY-Sys;Wte$UWhjGVj-^6(y6DVVh5wJ;aVsjdSvW3r;C zo8x-_qtL}*(}GgN(Sq_36;=mn3lpGxl(`;GU;X&*$5J@G6BdQFYUt?M!i?N!V41fj z)EalBn_4qpDyIov$=1JGtSWH-#q;uK&muJ&VqbqaR|>9J&WkU~)q6(K1r|{9uv(9? z5XdO#$zYI5h|4PAKF4fLk65QKpUQoyy~S7pkKZ&@8J|lm&+30xEw4M9>$Hw*H+60C z_$0@Mz5Z1 zF*_`6tp7o`K2}D)a2co4lPd|%K^EpA*HdtGJ({e^r*+J&HlE}}V(y!>rQs)hBHbFEVlsCvy4)UJ71QnsGWf=^c zCMOBhF5Zgk<`t1K{8Xw$?Pt}QA(?ho0n~S;^lF)s@!KowS_R^zT0N$790SimB2EKb zcLN5PF1?56vR=X?4)3Vh4!vmF)sy70RMJ-N)cvfzlXsA%s?27)N!%*loc00h*#_rw zLk5KgCXp8z+OtZqL8`?Eyfo|fc-!MF!<6R<7GHPc=7vwT-Uu2y#`-}jBkkghE#!1V9~ zz34XY4%dfOy)eB3o!W3Lidt>N9fk-vXUbQbu+H6hcI;*I+YYRp9uGGK((GFAviMa$ zlB-Jtlid00Y&ProW1dplQwfIJ&e{eHqjL%&o;E_U=n1(Tvb=*i#Z6 zkEA*Ncusnoa$&*>q56`6@`;?WDl7l_EiUWkIFg9*>cQEkkKH(%gFL(hhoWIVkk0NO2UR^v6>=bO5t1CqYcy~s3kB&^TpZP@rDdhkA0#XR7Ad^!W;b7xrZ;WsN zp$abdQt}-@IuPi7fhKgnKog4GsRs&5q5B1zP}J`O-}ehNfwL_3e!gGu37kH(_kF+M z6SjXp;4~}Lb)b{_-v9gegYDlBwtqj^{{3M4_k*GC_kX4E6ZNWpeIp$xY2o1FMiqXd zPRZFj28IX70D_{f{y(vij-tmOU}4`v`Ql7T;Dc0>OxD+Ue+swVascnClkkfZw#X5cRYJd_&q7s^uM zz>z0=_7-%g7zGX-^0ucL|CvSvI75*e4*ot575Yu%YuV} z%-(-61Ahe|Dm41*Mg#_&J-Hu$9AY3)Y5%v1KM<~t2x|v(8*2wnDH~^my|sb;s*I>XgRez^&<1a$>XVJws{v6h8FrW_j?_^p3HB^uv zyf~m=(;xK&0n+CWZ0I))218aU{*5%)Uxez?@DH(^<%NQ2!`){iL`4%=d=@D;)>X z=b_06^cwp+MW6qEGX4bDU-0yi^-#QAU^p)y2#Rd-w5PiuT!4Ge$Hfb{yinvK(*IxV z`pprJutT2rzsTz62E+IcXZ7c6$=lF3pQ>Ih__%~--Ls1M2+x47rB0d{oELBmlP^?~ zm7{mr&8Ox8y_D=xbPRHPMEc$md_C629!ZWzk}j|3$mq-CKXB`f>i1 z_@wJ6r<<*WW7WspL1OZK1tPnTJ>3=)bbPj6FMin`Yeo~Y%7zVZe99emH@la=`noOF zXKg7(*n9KK-PUfp-TYOBw&7uc57cv>-VrJ6F?gPzFNvITIQ`{SrjEnTitduj*`YXr zBD<6Q@{sr#5mgHfdATiwLyc%d+qT?3DHh&L-9gg z#qxyiXP0F14lN(uCQa^>$)Wc=yTK7Dp6wM|W) z!{N%J$pPA8CefsL)_yl1GZEg&wAJX?Y+!7i#wES<{AHrhv&-lRepAa&q-&VBg{sSL z_;2}#@f7or797`}aUcA^JYCE`8nN0|zV^ua`eeCo9ihgY(V%B2d-)ePzUZKawfFB` zS8CiM7GiHsHm=Ua_*54PRzDmle^Q}-Q{n0~1-#Ef+h@nIq5i5hZh-9POqa6pG*T8e zPmIr9o4j#e7hu=@qzmT^tCHh$Z@NX6&3vvbOHE zNNmXt!i~Ve$42-namu|fZZ|k=g2gO!j$?lmk`1DSKcU?$WOC^dIN$JVHEw%HC4(2vMwByj7h)vypaws^@H^JDmQ0EW?UDy$;@e zT(P|AtA1j^siOrgDj|^{7#M;A90k*o^0;Wpr}RkZPF>&-+c6QoSZCGY)dF^(>>XMd z7&no6qvotUx&mQO{K$>xOmt(C`i8gmt;`nPZsXU?T=#D(N5?;HFoeoI$RreH55IW= z6l4g6lF5iGohEGL7*u;9m;)xHT}etzKBl#1K+te2$?_GhqlMdj)hF>3n6pXJ%od@% z$BXzc!?YCbmyb;}c2S%TzXb)~l8X9(Ut=)E^1&?i+3oAcB3?XIw{3F`#5;51RS)jYL=N&G;hv91Dxa=Vi>ZCM8#9VNg$8@-ngpH z$mr`Hu8s^35^T%9WGN=<-%972^?{pUMZV?lhZ#Wd@xssFx|dfWg)Ly2@i+_1kH3mA zamI4|mVcO?Y7q}#3%1#D53L2!_AzYHarCS;O+WqH?qmr+1nXqP^rrD=xi?q0*;Y9M=k_;cv*S++2O26snhdv z4(1}aGghD~fy(+S8M0nc6RDnL%qk4Q{K;Ay^j6_46%yh~GQ|N*MRMlB3KbabLfXy( zWY6o>+ZShO@?YKUGBDNfwSklbmFl&;l|Cs$XYN&k&lKN;?%q0NpdGHPU1d4Y((*=F zjBay=E-=qwhN4Tj9b1FO3%%!|)~kgi&6`x4!Ed{d5X#Uf9nCK2B$T2tudu*27R2J2 zPQ9fPMmt3}F=ssLFB5vI2J-rOWSQc!>PmmcdB3+R?_|1hZ{XBY=In-CR~c`wq>vf4 zb1`MVosqj7{KA)j{AQ@HqjVryV)8VpM(jm1vrEbM?j^YeK8rkVJfm`~BSha7%2gfy zs{acuy&<@ND_go=%-K%3Bs6mQ#mNq(3Vd1V=tLGm8R?CxUd1Wvlj37ZL*)6=_u@Wa zMX6S;OW)z{&xxkZR;GO$_~Al)K%)Rv9Wz0t5)@LvR1H`wY1stpPe^=@I)p$(iE_N zB6q8(q%pY7h%e=zHeg)1(=A~-b4H)B1lI-e;lfEyIsba4{v@)aqN!xB^Ke*Z->Vxi zA(HN0H%XWxxT||dgES$V4a|6Ux$}Xv20oUKSNTP%#4p@Dlx%OX@zCAEY9u#fPTzWh zs9>7SLB|~hkxX4RiG`%v2Rs?-Qat_Xao%WL_jcK&_@(hDfsvVZmm&QemVwWxPMzfp zVjb{x2aYzlNFmK*ZKVmH>4B3HHdnt4oossf+|Gf*c4KOUcw@?Hj;z2dcc*G@h^_Kb zu}e!kEgze2brR%(c|z31n?u(rXJZ~2Wwv}=Qe^mO|3H(6PzMKWOtW={|Aeqm&u(#= zOD$Kol81$RC>cG^39aK!xa@f7Rm3c@(=D4TD{48WYs>Xbo^0&|YXK5C?74xFz4k_5 zNPMUB1b7u%)8C4Z;_yU&7OaV{eRs+xWM-}fChXafy>%tQjc7&;(8qE05}j?A1A2nR=y&R#MDr>2%R2n=-Mf$+k3fyOm3 zUf?ioUO2Kxw;rdsjgz$_(2I^!(%c^S6Ckeuc#txuoFVW9%C+}J(a;`&{3R|_(!^n@ z4lnlXNu_FN1PEty1%wn2_$!A4S@se$P_pnKm;2#hAh&}DdJu|#lZA_O|9N{at;~4| z@VNoOetP)f<&(XKt2kL%8QQxYJQBR$2K+yJs6E2@>+Ano0#vTZ;nzRBDzPttv5hU_ z+w=FbQ2xsEQE&Mh1W-9Dho65q%-?^$n}Z|53ZwumX*!!DT)s-OpHK52NCM?l+(QEO zwqI$1qS78MAaGQ2%&&#yK_%QA7V>a#y(i?}imRcuF#=?KK;nNRDZo~sQ3NXMFaIlIAczhvGTa!}y>yjE$uP;)R}buen*2JM${aRaj(*tY>vZN3v~k6wEKeVu4O4jPI_-zz*7gt3#o zxuY9M-o^xB2{N=c0jb(M0eVW*!NJMO))Bdy|4kwk$UhDs6xgcWPa*g^fB=p5B-$g< zSBX#=WBZ%}+6V($@epRH3*U<;ZfOqaJ9cG+t&P1S!UQA(NQL-!0)c@od7$qevW@>w z0_{zuZ?ySNAe3f4EYQ!YSRP?w?qmg0K>*4CfbATAeW;RZaAQf{{YePpT`$G`^T5vcI zjDzpDs(}Xu)WI0>D`!j2&(40aIpaX^z}10%@2btN~N& z;An4d>}YOn3UV|*2y+iSm!r4F&@mNWs2;Rq+0F zLqV_nl~af93(ww{?@>7X;y;^|3$BJ%ww4I~ZvvsX_oG0Ek|z&izvtiVbNTRtkT>}r zVL2O@pJ&wGIQ=INgB-m59xeB+1<(!ntJ4MHMOn~aPkY{<^w7_y13B(UEF2La2^(W4 zD}c?0-_i0n(gKT&kl#-u6r2as=tm2}^RorHWMj>aa5V?K5x{elvbS-vbpVMQT7$$8 zz&As{H8ere65-$gasax0z-jh9Nyo}qwlQ?&td8J@I5rj zs0-hZvOH263f*Q$W8UZN;AD_$vI~$zeZ&%LB|{E;uh7faX9Cf1SW6{C+)i zkS^nQVF>EN_p-|YG6O?=D8~MVHsE8cSvxq{?nNm7Mn)(P&}tA2hVudH^hY80K>Ur6 zD9dq(mVCc72z&O`8R;GXJTkNb{1yAJwv>Cn4(P`i)56ApAyZK>#w~qk|(rRpc)q8LJE!Gs8XQ{T0MtOAG~a1R!uIH#fk@ zpFrF*vA>)}d_S5J)P?Uy8kjdWfSZC`Zv%WNDTE^++kvkSxaj*tK>6|@RWrZ^Gc`lS zE8iu&0k62XjQI6Me(lP`k?tY%H!p&M_czf0Xmfy5RDM(k$oRw3(AE|S@6V^-pj<7$ ze19XyuO&pTHt+#G9e+jFe_@UIezZoY3*RHH{FBp%3R6Myz_N%rpuCVE?zv;%gxrg7 zew_GlJ}3w84-wH<2BV<*4U9k9A-?@u2 z&KCVC-v1Y)w-3S(0DV)*dvV0~q5!kX*wP7=rF$?k5Y#Tt&kz2^;?=>l+PD4(YIaX~ z9DeX2Td=KP(mg|#0Y2R*b7{v7nGwVkS-sEJ&OEr zK6p`9?8FHI=@VGbA3>8YX3AtHOgW1CSvuq4y$|EUz8@Mqc8r05S~6J1*Y|mND>}ZZ zCpg%9oOhUaJl8Ma%IoSRc|WeH83WpSayk(Z1y1Jl^J60`{oJ5#Rqn=j+vHzS;Z1fyTp zNol}?@Jn8H9K*VX?OK*!AWHa5oY>V6U-ecxPNE{3xAq*Fy9x;FmLdI@$unIT&i5Y& zci><_TaWMvm0ePPKPjE5p6LwkYHEyEaO8=;RdR}3rdz()O~OIUcf)y1j`1P=QUw*Z z0XJd2>L;h?r>@2(m|Jk1yGbILUQj#%z4a)5`&BVR;}m94OYLJl+H20RTUm(o>S#xD zK^(Jg`MV!FYR(w&R@04SMoPY(r|3tUWCo8BAY3~vj|-l+qWO3UGFqaIW-fhB0r56` zwj}&s6VA16bx1~!G8JRjv6^o6(CaR#)Sq-HbY7RRwBwj`#7!%NYt;{YlFo^3sD6a8 z(h%|nJ#*BFx97^)JKf^X=0-RCK%^j}9?#gyPGPo=X%2XxzxET+Hu2t~uu_Q|R%#k> zeJ!f?SZ|MErvW+niNR!59gHu&ECd<;WLR(UaLVgzBmFxJpc9HGa7H-nGZJuLynBS* z{r1`rmO{NgcLDLI5ni%23}^%9Ja`LBIEeMlP2$i-v#R6yym&#QR&m$PEL?igT=B7y zJMSrr?hOiC*3VCy7t9BPN;MJM;H0f z5IBSGP3g|{>8Z=WKPoD=jGLYKDsmnfaaS=ixicf@RUO-7Ce8!2c zm_6!at>}>465mtD=P6OccW3TRh@SOWdQ0>~R42V@rs->txTzyogf!MI2sVE%$B7({ z6Xbd$4sMA78L#SbH*rGro+xm-+#%ujT4~zI!);}AFe+o_s(gp<++nwpdc{MrxM9LB zZj!g3FXW|NA=$}yGt;wBA*KS%_en{9QJ*YLS?&qNIQEXq+ImoZCUd*3Cu*pn*gNQI z(O*9oM4#U|)!`H|@R`|}Z!ja^^QF-i`wo6;hyD&`K|05Xj)A_Qp%EkD+Z{d3g68ih zRo7voGOM>=?p(5yIrYjEgMa!Yx)Vk}+@KM0BimA@nK5QdLpLVQFl#1N_3oLA^4A{B zzS7Rwtiswko*rqjOOQ6lc@`7M{h*j93%gnfW^qv?h4BrF=YO`3SIOk7B7qxt5*t?4j2QulQ;_9t5>Gc_O-y%3g7|V*6euE(8X+{$8VpQK1zNB ze&k)^Jd@sXumTtj!;?4_-4|W=ywS)&*En(hdYSX>4%qWdc+qFyV-*~! zIf<_5SZXBnH1{M0o_E;!?ki`h#l_GCk4B!FCw$X{b;kFhf#7jl;sv7AHc|z;2~e^j z7uG!Ny1)_mu|(rFjHf!jrcrOm67VyQysNN1H=;9mzA8JocHFj3I$*>qd@e1jstV^3 zkpcga2LW!uBxEm+Y~hUvJ#9Ntn_h)EZ+s~dcg|spE=a6V#33%g7Hi(Y_w-R_l1iNU zi*#6x1xLEkB9}a_kM@kB$DFTuhxLfUxBb}(U(IyNCf^A+j1qzg#rx;8aP_cCn3j&A zF`N*OGtRh__S9EJOpf#E_W2eP^vDsCm?L$CQCaNht+!GMPc5^7!?762&o^TgpLuzb z?zl3ubOSS+d9+M=1Gc6N$b~a6a8r7moZFe|g7Y!0svEj%NBB%wXV*ntPn6X;^D7FB z;NM)iv_>R|QThBr8B_qji8ulKqG~$)St8#Am+N{B$$8JcJcZ(h2QjC}xKHuU`60m=Pz5K= z%jWq)Ps+;;J&R7BLc>pa7RR^HZN|>6Gw%@X-n}?fUoda;cuZrxd`n=6<$S7vAI@2^ z>x^u)s@HFD+|NBhf={dLc;?-O({EJ<=_PNxH3}tVeRe}_OutZj@Z4vTtBu-)m-0v` z8YK&5EQwDCvm52EJ#bZ=InyZwaIT4Y;U+J;K9OmoPw?fCp2q31Q+DcGlF*PP_le78P0#WBMf-##gfpm=J44$$ zb67jXI(4nux)MKLwD)+fKD%n+A#IXL8=@Vkexc30sNm!stk;@qf$)V7w{PAuR%?9T z#;qJ!yIUB#_VG(SmO#FJBIB7>)##a=MWZ`Xr<7VOYV4oavBxVP0Tq-1&9Swt|ZbYi|O`Uq*u#ay0pdBNJUSvM_Amy&z4 zX4&Z7=b(HYdxTiq85Xchz>4a7y;3@3wJn1O*#n(cKI$M$%~cs4$H|%TxoRDkFSi$%?J>UZw<Pk zN&?y@W97qMCVDM@@yKT{@3gR2ycMb(Z}Hfu^?tirP6<;8C2{7H=MncQsCnHdN_&er zU$zZ&nd$al~F*}x+_%o+fNqB|qQEBL4rdPyewYExQazqODOOMs? z>h2f_%fhG1n4QcFPokb@g`Y}Er1S31#8axC9|bmSk_+8b>*0!PPc z!e_T}h24Kg z##GDsTq94uOg`=P(R?v?k8NYq0f(tz=Q308(p<#AuA1nE+`58&ipK2Ese4eaLu*EV zDbV8PgK{4Zv}QH2997i_s?|iMe9z+rr4q=KUuXiyK1woS-&D*DN zlP;kt+0_wg*j~mbY(z*XkxHPenkeDp;gO(AV7|5E8(;As=6kVS3z3O<^?zu43!u81 zY;8D5kl+v?xVuAecXxuj6N0?|xN()vC3h z{d9Nj-Bo?MpVfQSX=Fnb6dp*>z|s zj&ytXlIv;cq`$ZhC~$qo+AKxC8JiA$-PH^s67cj+GBa)b9J3w22&&300l3sr9AiwB zyKQLTm4)Hz1UVkX*sdYeYWR(pWU-psKfP}BFd`=S^IB?pncP8}cCdiy#5m8x7x0!q zeV!7-GTK$d%$=D+*J16O`aBcJ7Gs~y==d`;%C%v-g)90hZc3M4sMUC--HyqymP<-3 z8N(2{vYqsi-iXZG7NU8{a#?DDgPZYQrW^7Wbs>Ex0+;)=HW$ros+JffuDI5(-p*u( zgFcu7pXE|zW-&-^8leRy54#>Ym|*v3E)+ZdPF8gGLC}xrV*5D+B(-NCJW*6VE~IOV zQQ`N@w3v<D_PNB6#?->4~-jI%_|eqfc~U7v~V;YRa{ z9iZ9SP~U+Z3H$ha>b7iVsAt00$PG*Gx_$P1-`Z>|zChfFa*I+FHO_zL#B;#$Bzh!T zRrUqy$6&_dp}7%vYwy;J23kLrNa5)hpWNx0f^I!sl-m6@oRtE*ysz}rgK~DG6~Tja z;`q`0X*n4Hm*fjW4$cmrvsVG=^jt(&y1)Nl}tkz15KL5|YCTU}q&cEpPJ z1JolaF5p!S5OjPH(BSACwm3NQ8jy!*FgdSXkJ0(#*EwPA9(pBj)}=fK}S>e z2uJW)m1@TbT=M7h&`x2miaAsKhnimBHl|%}d|x%*@;8nZN!B^$4~#R79a-GJbiC&~ zN5|QG#v&Ue?K6Xn#4hOh)thRhZMphm)qs{U`O9cz(jb>nfgLG5z1jCgwf)gjkZWI_ zzT8iq&)47f+}j&b^r{wwm8>-=w=dnjdWMnB_yRq%C9+v2EOkdC0Q;i5A)H*60k7E| z(=#EgEW7eIfma=`HO)=mHM`jzT(5dBeqO&@C?|?j?r^saiM)L0`Qa%+GXlF&{-c->ETsvSlp3^3vBnR z9Uys8H1JVbTyj0HIOIo=R5fv1+=qkW>0$0--&Fq+3M+5zdk)J5)R%E(_UZvCR3HgY zr3B$k*vh!peaBTA=MO5e31kyD+@9u^BGASuuV*W(Z?b@J);_{BxuMJW`6jM?l*Ksq zT_bH585`Fx*wl>mzBjL7_$xJ#Mad?H1l{q&lSSTg&Dz89iAI!9@k?P}z=_u_>;T_^ z3#65$2jUsd>2!h4`RaDNCKMAc;@pC2!l0EYXMGJFE}1cRV4Z>&BiH%y7(}Oq>~UI4 z-jN1kmxrOtc|XhQA+Lu?TgimI2l4BXLOM4EvMu*0tM%D3X4O?v5vSQtZuel23eQKL z6QCyX=cHrEQAh_rWzoG)F#;_pJY9ASKypELea=9AphldQA9}2t|BR@$a;BgyF$bD@ zsXhAz4-kKgissI5K=TY*I)X?4!cjDRSO}uLM<@srUW4`*tUB~6eD;Xz2S{|#&pM8g zoo@GGGyp1@JQl6G>qzV_RGo+__5qD6x)3i85rglpTqp&bpe`g78nWO#xR%O1>^k!A zW$n0>z(z4$Fp#f!4+)lVPoEAO_=+f--%$Gx40tp*Sti`NZ;arn&?hQOQ0)jy^c7p6 zzAju}g@Q^=uXbfQp ze6rUG3y=k(h*%H%3j+tt1NJ=(2thpqsD(odaOp<)khPK5=(&+>f^mHs(B1bTPluaO zL*3yto_B!0kJgm7*BQ@d=fl_D8889M9ua868)zv1-Pp|!3ju@(jlFeI?#Qo;b8cLr z#R^o;CRH^vBAgdBbwZ`%(8)6Xgbg2)KS=w16bSd7OIE+BD#+NhASQh6g>pXfs&=sA-}Dq z6bs;WHaN?cx_8HBxpH(gL(Lw^ao}u_V!;tu!X5s9aK&J@)0`;k3>~Y@Cunzaph5vy_-LQ|*vCRUBNQ z%HW7=8X+b?Bu#{eS)({qyf|D9&`&WFDo@?dFjJ%iE>}TQfUMXHVlZeznVM znAiaVQ+DlYnrd2>Lu>5FE`M?IMV!5IjNLoXA1BitnaSglxpLx&8zpn6x&)ZGx9H}n z9pQF_FYaP@s8-J$Kh)X=tp8*`9Cwdcm*Qd3vzb}BLF`aICvIvHKc9QL_V)6nH1p#t zgma4HtB5%;G|U!vD&;GVIYxUVy_{5TmB}Ihq**n2(5+L@hAQF4B)`yz06=xtbr zbd&2{NPwn=H!Xi%<6V}6V#2CQ_FBCH?yzt|$}-XK%(4|XE41L->bFxDU+IjMlRlJw zdh2CPj=#ua-Q7D&N6(ViI_gZrw{&DMpk-C@m1g{F1)J&Qtf`JmTD7v;cHU_YgDjox zuDCsg8HLsm{Ic1gUdpoi{jX7;`jErA=}LOl%#|avo9FVm<&!i+9sN!zxIMhZ7g132 z`JR@Qwd_k;(mcEAbX;Iz5gfj|qvVUfzLS@ileyqp{A~9IYCIe3x*qUx?y0fZbIKy& zq40P#<<2{)&NE@b$=YJ%K0>+rmAtH=yFEwC{ONUXQhEGvzD?DCspG1ZRsMXnzSVQ~ zIZ;g~WdGXdumVUAF=Se(sXWGO>Yp^#qOYxy<4rc|JSK^Cdc@>21XHhLKhp-4cFb+1 z!M~iOcQZDxa)nSosaYQ5rdpenXnUCCKremBekN^MUVc0X$0uudzn>;QDYxA0cC#E* zdZnFq+gX7J+W`v6Okg#<>iO)T7k6XeZ*n5Xj;8G0S_$Y-6`uaI@VcM9(n&hkekw6^ z@0pTxw*$N{*O~u4IC9yiW4aqNshWk!Z?JcLv<>t1Q5 zT*|zdWb6GP5BE9ljBR1l4PUyuWRrNo^o&`lxu@VuKX~2;$#Gn72u4iZYrw=H9==xps*E6p)$=Fy?34vr|flv`bnk9isNtiZC znEqj6r&JzOC~_7%X0&*fT59W1i4RGl3XuIlLUZ9NY=TP_aQUJ%5h@i!WuoQ7aGi_S zo$RSHmApeU*-a&*{QDg~ZFjG4KId6)Po@BJS?a!z_f(%3!^NW;@bqTu5Eb^orWy;x z5+g-ukNg%{KC~vu%1qklr1F2v{r)-OsL-tMS)s&qQXi+LB5d@JT=ufweW zBDO?!iUd47FN6I`dP{mZBnpPIVtInln5avyOzNfHaf{vP!WdJeM>CnPsi%``MN`-B z-8i-)5KPI~v3F8NFr<5n{&|RMCb}SWDQLhr`{%07(;C9?{VUdK0?aZCuDUTdk)YC`m7ln3-@<83Qlj=3mi?=( zx>1!cENd+?yKPlSizQ@HvI=?ER!gSH9TRkaj)(fad200(nL0)~i=;+=L~z~qTnV?H zMH;xs!-&d13`V1eH0~JM9T9?Jj$^3AVzvy>FNpR>_9T(!8;hFn2aMC`*P;om^q^LPQA6~I83A{)Ft1^))3D6i`=9>@h|LaV#pCfB;yl_$OJwm(+b(C z0~ygveC#XbjOp*=iQzE-_8k3J_uw`D<*i$8e^wUW?|rGaVN67)?^cUPTpV_?db#I4 zm|+?6SbbSczif}Ssab(|Wbb(IY@`+kTkHUDyXp?h2)ht@LXKTPs`)xw5PD97g$0_=z$nGK*s%5_cMGm7W@)?Hoq@Q z3TJUGCtgVEm6i5hs)6}Qs>N66beW)HXEWAPZ#_-@;xCCV`q5K}zxu(HCa*ufi0xLf zyE~mh?a(3KNmaIHRr${9HkX>8uoe6yR51xEJ2BL=D%gmvm&G|qP5wR#7#?dLH*Z*i zIMdWiul&7Jn>ORbwp4RetyVrWmN8+v?r86F6QC{W81fscm>V_&_R23JY%f7urQySu z4;3HQgeAbTq1NDdgd1R7F=l0c1)9UYM-lw6>V|ML%$q5>yQD5em4U1C*Mz`{l5gRw zei9^_1)FZec+pm$Dk)YWU}!X8S~zPz`Cm8q?GBbu_+kpk*XcuBDM3osXyuil15vCL z6$BRHP`RH3RtPynz(G%f+=K_jYBZ;ih|H(N?Lx6@7-*;D?NIJ0lwfQE^m37b+C2?O z93l+__EQrA`f%?S7b zE}yvsp{_WfXg`vFi1~mnLV=YaP~y9jiv)8AYXRo<69#`LP>6u$Coxy0KJ%8>Z_IA0 z-zmtDc`Q%?1=YT7V0PY~6kIrT=J1!N-}NhzMRMVOM+EABadpq~iv#EM2Z4_q(B_(K zminS{p%kaJ?=x?Hf-#3h+@XhY5Q>G&VS?_JgimIL6S8B>fWLRdvJg6i`b}jxN}Ncc zWXuKYbQ)={!7bK=9O9}SS_R$qWYMkp9>r- ziYE>rW1Wt*R*I%ImfmzAoplqU`@|^IdxYY@#X2%~Lv95Nvs;?t#Wrk_0Ze4y6dN0m z6`HXgr2B<_1^L}(2=ABj1goBQlK{vv@7^j7(!Ms(q}27*o5$Bgo!+7Y6-jEMa!}ay zizTUoWvv|HqoQO?%!P+%q&#H$oA1m$e9le`__W?Od}ptQxj9PrD>j$rCBiG|Z>v}+ z@*v`2AyqIC<&g-cf?0SmJ@`@WXYor%BBvs2@Qbk7EO(f(yF%UBj7Np|51mnuO8l*< zk24>@-lWY5i>8adhC;!iNEA2%a%BMdKd_}Z6Q$h}e`4~AZGD0}Q0QbE z)0O>v3-f_25ADg7pI|fKnfWbTZ%gfg)jJF65=V$-9oT%o;2F5F=Mre&J}Un3g-r-!O;3yt0QMD9 z;!tCh1KPTe_0ux?h%}&~A=$~@eW`LDAxgP5Ux@XbrBFqaK>y>zZhlr03e&ONNeX-BWmYSta!_N=v@$ zfEpG_=~xZxTHS2w*cj~3l`~vU9$OrQ;`tctdu7bNDapw6z4l||%!~84_qTd431`fc zS~Tq>qj5K#J{6WY3qB4#=8}31GwMunlUY*D)8XVSb?k>}u$WH3{_>Y}-?o+33@YHM zG#fiz&dxw>7(-&6-=2u%;dA|F?@*YW@6>GWrAcw@)wp{_eADT!7O~C=YPjhZdva3N zVWFwYZai#hi@yO=_+wBwC3^ z>yBh)1Ka?WzOLZ8-$BaOp3SJLUkmb6W?WAiHL$K}c1ke%Eii$?(VkG#{JxC#$zdMX&kDya4Z)_VuaW~oXEJu z+Ei9Zyq{hSrRb+b;|Ka$n%ngnLkM(qbVZRu7zw7$&bx{F(FMJS_H%xQhcR9=)3eO| zRqng&{nZSj6h}wx-hO7dG{)ju+0T`*%|2;8jEXZ@doL-XwMN$mB;47Csgo7(eZVMl z%>G`tAho!wE#RuhNFdZL0H-;HMFytB=UYn249+(W?i>T+bF%#adzbxdmAf#a{4N>9 z5E*(A+3+RlYa<|K67NgBn(H=qXop~MZRgQp=4s>CXtHLZIti4enZv`*vv4p1PQ779 z6fE6>>W!{sgD{^{U}q9+-Z!jba{xs|2|3~$4K3RVyM54u>zIqY(!)+>HN_Ls15WQ5 z;!AXhpX`zgo5wLp0&uTOU^wsbQ$_&kO)U#X$xK5a#@N1>K!5p5z$LRos;-y; zshH^_tS;HifC`F*Q92d{mF48oNtff9o;%AFR~o*l`}?VWn`e}UjUj~BXpjsuc)ysV za-HIh5IG5YT!$ZmL|BH=X^_KxwEYsIH;*45EGOR`4?KwZq1Ga|K8 zf=?~WL$e9xbbf7b7J4~uV&^VsoHGsDll`$di1s;;9BUQQyoXB}gpLc1x=(>R-gPlag=l_|I5HcbajT2Yb( z1=)=xi`K$j_3ce6FXy(N4d;FK>nVTGN(_ z^%@qQ#@sth$6p1I9OK(AJc{4j`CLTx8ABLja-X;9Je5$ZDyOx~|FEoWG@zV4XXngMrK0d!7TO+lRWhs7C}B~c=s&+Z zf7$TyehGf zl@3l`5jJljnWgQMD-O{^#$rpCzUxx+O?sjMhw*35l6+Pjb&~k9ALH&uCA2Ps^0OK8ABF zQ~wn<3?>Xt5@7_E>QgDa1&m!_CeAdzz1{GA?5I%Hr#K;ZA=AJyq!uDzQ*4{i8G;5* z9T9LU)=WtElN$^0C01Uz^V1SKNP3unNL=_85dpR_kUY3JWG@&aL^X&lm@Oz9lR7Z^ zQx-B8X9J50BCC*Dur8Xr(Sg9hTHaky72Fy!*Oy1fgNQtvKx>3Gj8>BCr{BDJPr@;Q z*`JJh^LtTyr~5#?)V)W2CkB0e%e`X3QE(Zb*;vQ$ibHOK$C27NPoir~4DLdBk#8jy z(F`VoI1$7eWBbkKQ99 zB1$S!C=L`&6j2dhB+f+H7Y{`#AmJh|7LkciAZ|ygC&mz2{cPvaKOLHca!kS|%7b4^ zww)B(Ou`p=&$FEoN(x;VC-hBLrUN#XKV=+jWZ%)h-zo9 z<5r3}iO9rp(*ah-xrkMTYU4d90QZJVi1k7}c|je+^2E*J-k1*#!1FjCvFyleaZ#}W z@gmV(F?8{7qO4-9qFI<^B2nS#$gG@YEKS$1ZT|@^~7J0Z!Bm1ei|tXCo4!dkd4G!P}L-Ae5cDaNi7<%&)Y>E6&XcOKExQG zwoEh9FmD;CTdZ5H1AuY|%-p6y?Ypd_ZOJiodYYY$Cru~yxJ{Wg&uDlkc$it(S!g<+ zb+FcuPeb|GTX`S14=$%tMD@_=MDIijJ+@+_4A-!iHtcgRS&kKT`7)XGI1MuhdHZ8{0?if-G$VE8~xf?zi?GNY@v{5=sp77RM8WKd~MS5}F4lJ@8HV;}y ztf4%4on$Y*)QTI*4=~v&+QHf#+PT@0+0EHCahR<>*cq-KaHy@K+kMxzS#AGyyki}q zh0@Gtt-QKpS3TH)b7!}jVz)7P8oh$)!f__D%72M+X?IzA$$2SynRJP88GY}tv$Dew zO+etI@%-&l$y5G0^8VqHeP{!#i`d)gS@<$zCnwy8==J9QZks=B1OH9udGfMr=ncz< znTU^wj)*;vBab?dDUWKa9g@gEr8h8e1U3uS-an3!Wh*@p2Mr4KOzszhfllvW;1FuI ztSjeMWgrqNpY%P~R!E>88X_sK^cN|3*+@AVsWBN^30mn2Ss-c%Sre&ls;lI7e?JXs z3B~uYjxYyQO!D>kUmSLB+hzUGXkKCRFC|mRbdpHPZb-)^(sLYzr>!Ji$ks9%*eryn3nVAW zI?}J@ro|=oNKa)RsScY9g(Zg)CP+glhR91u-*=`HXyT6(PDlC@R^r9UW2CcVc{p2G zH00Rg&B*ls666Oo8WE<-qne_U zq)MauNQF)nMKw-UNrhSBSg0MhEytu}TB4m|uLaPdqEW_|!IE)f+nr0iQ{t0-AUAOV zye1k^nJJMdqbb)bMJSakx6E#p3LT}+N-I}OeN*yK-Y;5Dbr(MhpKUD7P|A_ zinrxs)*;QbS_yw*C+AD)HRiOQybr@m!u9E4+w@&AfgFEQkFkgesd1qh&?M1#)^w32 z*sQ@Ma_mbA6P3~TVD7$zsT?MToySN~ENSMm5%q*i+d=)o87v0V_PAPBBdx*c$a9uk z2@p?t$`{IN@?oNJORKZ@qKKc07(qn$2f}rl! z_;i#j)#>Z8@qF6J?~|V=zfOQBkteG^ES)u+ot%Z)a@I1vbe*+sgO&>Fhs^ZSz1*D5 znz*$_Z%rqMvopM`ZljhW>M+e1#yio5@7e?1M6^a9Q_{GM6|P_Es|;#3$-9pB(Uq z-AMPtGWYFu$K5FQ3o;q(o%fy-ue2ueGIu!5?E4&y9F*Bkc{z}x+a(GETr#k2TT5BmimUnY0zljB)Liw)3vd@Z?+WAAz`_)x{`;;4=n=+_)m&$FuUBe9yWDRKJwXs+SwBNX8fbb_* z;_sx^SKJ8pyt40P*JIo~t`PTLl3cj>Y5B?dIr(Y27`u47=yN9dDY{tS@}FxTQug%H zHnOVs?{+80yXfEMpSiEpfYlQ|ls*ox$`1^{uIxA6SBi&~tFF;E&bPZ~{ww*tCpcob zZMf-A_Hf~FWuLI&(mzemAb%1=m!VA6{;ffX`Q;-ETou)?TK(M3GykVg^XNZlT`M-1 z{8Ql8sqb?)>;0?YyeaP+HwAiX{quT%_a5{X_Kx-X_ty0;3su>w8%S>j1*LqJqixT( zb)Z!?yHQ1sHihxVOtfKa;`K@+uymb{+joztsZ?}~aw1II(zpCc?>q2CUe;&p% zlXWiLh^|gm6Q=_4xMkk?cwqi=ezZbOgUm9mGRp+ykF_jc8fD*t!O;<)`7?B=9Pl>JgwRrfOqnn~yoTj7G z)JgvPNr?2V1?C!4FQQ1Fd6lk3rW{18F*=m56{j#oxg)%(A1e6|e=!k;4c(e?D&f4WLu@(x&r6VT(+dbi#WY_o?q zW7yEFD?WQ&W^ca?h=snvFb=8IBypN5@l<%}6Dp+Kg1h zeR_v4E2nFxf74Xg z)YVi2q+}~EYq~2QE>25JSJR%-&q+T??I-K1xmzA)712nkrSPe=wp^D^V@l~UcvW8~ zOrI8QB)w`sdK~5yQAod-#F<>0SeUe!448Z~i87Hj*-wHsDFBcs%F-XxCX7bbrI{=w zuBo#rIJ+!)nH&Syl6h5ce=Lof*d%!=+-fW>nD8gQXgcSfs4pqFnY%fz^}=X5#Boi)$Npn=`dQMDv~^)niuy5|Sb0$_vg?bq`t z$Y#_f<(!6J+dKa`CplZ0GdnX1+0~b|^MBe%G3dE;}#3RXMHZQgSLwFO4pf`zcpFQBGf4Rn_#3 zyL_@5qg-6gMMb_eTeVWfqulHp!_Usr$J?W#IhyhXHJdW;c6aF;nmHRaAN3cv8}>PV z)$>X|^%u39!}OZ;)O28aMS5>KD7_WCb1yS}K0V_5;Jmh`gNdw5lf9x|Zcx zg@$5%>t0^E*>~MCxB9)8ba~6pvZZfV(&GfI;+C&f2&Ij)$7{U zx1*Q%OX8!&jZ{aox9W@kW5$t9wVq~IowwIZ@#D~O^K6&Wo7l_zqty-fQCIbba#z=@ zgzyhxDPiY;#=QKz&YpF~_Pk01Msve=aaY<}>aEZR&Y1vV$>lAy1cm;KZw~4hW#44bv#EM~gy~e81s{XXb z%Vx!B#fICEdw}`J=Zx;+dbc02TI0*=6drsubp=a^&Y!rWzNs^CN9c5~_peXTo2bh7=a@NG3YY}oNTbUFCgQ?#&nau6I3yUfns zjs3o%FDU6+_^m|&nFz;idQBM>6-DQF)pQAF(jSOlV5Vu~Qc`>^;k7r);5NUo{2n;Oov>FY=wM^3?69y3Fr3@ zfqJmkGvT72KD2*_oByHIh7WFCUnkz}X^l;Y7qt7ZAHIEeC&VpY&AG1^^a=NGaA?g< z0XSR%+YdcNnRs)ExnJ|pWz9v=7&CmAAjin{*}&>cE$R;6wCgi@)(*~3j*iX_b39aq zSyNql+tHk}YK{ZRD4v~q6)AB4;#zxQX~t`&;VCjMU0JXk76D-FKQz)q!YDZ*sqRtsBh zGgt=#?<$m$732Khow=!2H#t{1LZwwej@3myp6hA1CA2R0#j@W5V!QKZBSiJTQt}_N zKk$ILf?q&x!giziQhfMV0x}zh2gQ~6LS!?n8x4#UTmmu{h7d)7*jMC3*auWuLJYec z(N!~)yCpG1|BxDC4#IT8e;Nvq7swA9BHkErIif%_l)u47ut_K$oPSp$s&0lduMy~k zVUYE2U~<4!=oxK3cZ9$Macn&dkQSWtPjIyF3z88}&t@pC8iCdrc^RSyrhkGN`mM0Ve|4KqXvpcCto|GkgcDp~f$z?56Ve}Tg4@q` z_#MAH;=20K6Ix>K75M55g9@xcH^sFT%cND1W)f0LvEr3tYlT70Wb3 z+5bzGk8E1MKhiO-f%Bt0Ye4#7^yG+Mm}&X_{uHQ6=!>Gx2o5Kv-vdMY#n0*^e(1Z? zrMb}bTlmBi3k5f=FNjSm5%AHXh7bYcYmYy<`fo_MbbUcIT66!8vNgG||DOEg34eOn z{~D@7;&b?Zgs$2AfPvfX520@R0S-~W2dsip>ixfh+uC?$Vi!G%ov1o=Sa_^EJlHr7 z)vgb(^GoW>7Y>L%d4*awB+Laq{9ZB+J(6;X;Nj;(T!zs6N{N$;_fSOnaI6q z<$AL!!xQpl)SC1o;$Vb?4&LlW#{J?CA#AG;g9zXApU4UXjz8P{)EuwQ)Q#LWe=<=| zu&*QsBP=xeRyQebY9K^{tv)KEOt0VH$QrrLzuK>2K4G=u$%C0F{E^h9wQ`pU*!+MW z9I*({bz1^#xWmB^OSbB)wmiQDd2xS+K-}2o;v>%X`MGl_AVD8(3H%SFWB5MXW|7rr#xaMIHbauI9hzQvM;_r6vH$l_4nCF5Bg*E-i6c#TWt?#e*nl-0^$!J3j|e2{+uUs! zYFWVnER}SKa1t25r2+OP=t+nVY<%Vu7!8JSnzbJ*Ys~Nv9*3Y_i~_7{1-XCxreiaY zMZh)=fNIGVq&JU+!v^{z?D;3RjSSo!1n7i!Yk zq^6EUeF>%F1V+^vl7{``n)#=E_K#B;{s*#x0e`lMTtTxMorzo%v)^?r=1W)&C-9oi zP;}e@$ytJ<;dOd z_Z{L2gvPocguplMCRx4;z2(X0-9W7&79g}H`rB=c`Q+bA{sT;cj(NA(NfO`{%rQ?d zR}4Djf3gjHR~tD#TdYol@~|OQw3teA{Bnf*fQd7dZ@ z-LmrJ%eR!XjHK3(~D(99`1{i?)ty1F25abvWn1hV%2P9?LZWT1fIY=2+uz$cFFrG0EFc!J)NHoSB$T5x{ zuy*oIgICy8AMm}L-;g{q!g;W+vfY;8x@Z@SqCw=FtYFoDC9=_64~hs6B{mvHLL9P?1bi9=>@d{VQAB`?nDB3OV6v}l!@scq zq4Gb`q3Fnl9|P6@*0viR+4du(HW-+iz+YgHK)2{W9`aA^{(qLiz19E zFng#y+Qg~SkPcz`^eAIw{w?q1;+L9f@TpHzP*aFR0;#$Y|0wxu^R?0klbPV6euU8{#hb53I9aKArR&w{D-oC+u&bFg0M{z6i-tB7?F!O z7(Ub<0pc$bkPu<|gedT&{(d5iu`p1mg1p2W;tkM|J@Pe?Fv%!A%*5(qkfWjcSSYk4 z{w5;-?_@i%znaKJIE*ez4-K)aC}ef$COXQW$$S=HUktzhzRr8YAAcWtJhss=6DU2L z@9zt_AG(Q)l1bw4Ao4$xgg7Y1B>q1{VxwT{Pz2eChs7Y5LjMik$2t2;7A1*&^gY`oUBNF~K3>%IvUi34A&c<_f z-dy@G0CAJkcmG2+ge#)DU3WNyDsIiTFFJI^*B&XfcQ;9XzXZvjv1x|({KG#-R=^xw z=sgsBpYa392|4}NJFBWLbD1YmI-}xfmnihWQZ#yOrr`DNlw;b?_Y-1v zxlnK+kqkm?1-=TW;xGQ#vvI{`^Gp_)$RJc0kwMY$#xaHH>>>yM#yEJX!y0j3rs1hJ zzRWmi^=0QCkUpR`Py2p+*JToGM0JIRr^)y>jU|SjM*Tk(p>+5C=*E1nSYvt_#2Ufy zUeRED8}7ZLI@o#OxYK+#p5BcAq_RO3XlZZW~QmSV*4e_yZ>H_&M$op8vC!UlukAFxSuf{gesYTl)e z2%HFw2#&}H!FPG~|NX4~w*B>weK5ws<>8vy!!LxeHU;&acC7^~^QNx**VOT=HkBu3 zb<62lO`4i@rXy)4^^NsrT#D%l(W)nxSJoERxa&RKy<}uUR;{wCB&7J$C>$!* zcy$IH4f|)7$Y^-i3Jv$KCoJ5X8z*h=-qXHLn_6Ls_e!QoG@eFg@F2(5mgd&X=8~$; zviU%+T?Sc3V>Q%X^Y})|8eu%!r)Q@*My#vzaBWG4YmW_Qx}|Lk%j?_)(pQeRX|BBU z$tb1?78&~E2dCw%3~pTe$d)hj7PB<2zj-_6xe8*EXOj4;*EvJV@B;$T$ZTt+*?;o) z@4v23Wb?VW*f4Nr68{_?}+vxkorCL7{~N2^O64jHM9#XTOW z4aY@_+d;9{7Djx$GkP4Jl8(+8uJy-ti8o^7oR8h{w&#(Eb_2Rb;%0=2%OgKf*2*5Q zi6K5V4`h=KDfgFPhOP<$rHJ)NhsuGjVLVsZan-R#Xq-RaY!Y@5l+N*p)e?+2Ir&J3 zRF&?Gi1``cI=}SM5)DxR?=x{%Bwp}Dyaj<`#9hQg&A|I~9^tp_B{};FvLPk=XOU=~ z!gXt60>Yum{tYr25(msU8%Ef%Q{eKN$Xnt;LrgNt3p9DMTh_q_niqe`ZBzIr=LU+Zv8M*Lgq}9Yg+72SxC$Gd_Ypxebfh9v;lMABMq=UBC|_+{m837 zGKw>Xh>cd)ey%T29s5wP6P6-?ES^W7NSG`*jAESH2$1%vm^q&+pRSI)jIWHSjOi%l zCke)2Jgx_$wfpwtY}Kq53${c5>QOI&G!I#GGA(sWrExCsHlAAwj#gSePCu%$RxOZE>s>wa)?d+9S68C5reu0kZhpuPO zde02jzTb76g{+?c+HmUHUqABRc=3A@z7s!-SAo zw(-lQwadxpeRy|_z63mp-^rh?o#m`~taknKaXNQ;+gsm%UF+C*33>8;%6*D`s(F&X zL%CDDW4hBj+c`r!OE^sk{&n>k}S^I7!{ixVnTppyBNLR=_8B~>Rer4;#@W@k-$xnq+qlmavojOjch`Cg|ES9>6x>U0) z?t2kesqXh!Y_g1gsmy+9=Mf@SNx4!DZ1OA;gp`S-iG+z1`dH0E)l%8-DUgzhViK5A zn35z#5k-pA<`$8TVP93TDWX!yCGg^<(d@OF zsXg?f_ByOV_EF_g z=281m=uv5z{xr5TzB9Qq&RJ?hYD02Ex~-6)kf121aBX^W8vhXUP|c$HI-^1UQD>Rq zg$OSeQ7WXcZ#rihfHIuY6Uh!hZBF@#6gZ&J5;f+?fPI)Yb;`)D zeULVl+Q^)Jls3)6$c=r#D&>l?>YlM~(g_RF)%GuyM%({Giy8DM4K zMmwC(Bh;zTDS=O=M;j9_K57J%2G)W&+}e2r&ti2zA`eP#@t$cs8rj5p^m;^kRPssH z@!Y!>_9;9%XUS`Iq@#7j<#pu8b>e4n2un12bawzR`z{{gY^uq4vrz|N3y8<9(=)1F zpi@njzjM0UEfn%MBa=Wr0v1=pU@zO50_0>8oSUIQ-tsbrhRF71T+6>zOY({KG&xg+e=ObFXce_YHq}>=`%&t7p z3RD6z1MPz_K`9_-w~*(g=f>x#cI8*qSGiZ+b+R|YH_A8C_cKY8?}odEy8s@$8$d76 zImr6~>A}}ifsd3R`7JSKSbWzAqzAHl2=r9qBYUGm8Y$Uj0rA)A86+Z;slY1tCc%&? zg(=ZWHJ}#sQ`=SO}Uq}oY>l?vHbBBxHFPDmV0907dZwcq`; zD`iq0yO-z?@X|bjdXhOJW*;)})D9Jgt08 zd5>m+5-!m)DG1;MxB(ylq5!ghaR42l5hiQiUw7Ivg^LN={*QMC_G3! zs6U7-6?>L>7QYYsJkQb}YR;5;RC+WUl-x-+N#}{@Njd-|Kny@0V7+T*5(A0=mDi~~ z$S##USDmQ6Dj-rqCkX=#cI9_N?NvC7pNnwSDkPd#6~Ky6W5)i$+V6;x3jpfZCR!6C$)iLTN>R5H0I$oWicBn3OqI#)1 zNxe*+tWHrcSFcd7RHv#}sh#RHwM(6@cB^hxQe{<9RaH}U)uZ;PhU!(XR(sVxwO^f~ z&Qxcqv(-83Ty>s0U%f_MpkAvkRIgL7S8q^nRBuvmR&P;nRTrtZsRQcm>K*E0^-gt( zdY5{)x>Q}JE>~Bm_o(-(_o*w@`_)zIYITjeR$ZsAS07LxR3B0wRyU{{)lKRns!!dl z4yuo;kExHVPpD6-PpMC<F;Th!;&=hYX~7uA>4m(^F)SJl_l*VQ-FH`TY)x7Byl zch&dQt?K*g2kM9FN9xDwC+ar!Q}r|TbM*`LOLe=tL;XtqTKz`dseY?|r+%;QQh!i? zRDV);t3RuI)L+zJ)xGL(>OS>%b-((DdO$s>9#Rjhf2v2+qv|pBFZH;3LOrRTQvX(m z)YIx2^&i!*F(NeWEEnUmdGPNu% zTg%aMwLC3fE6@rxt5&2HYb9E#R;HC}6;o7;{dD{8f1zL;NsPu zwbrZkY5m#^ZKgI$o2|{!=4$h_`Pwzw0_|FDp>~~iy>^3kqjr;avv!MitF}nHO&ic| z*Y403Yjgtwc0vuz4n0ip!SgVu(my{NsUy{x^Wy{f&Yy{^5X zy{WyWy{)~Yy{o;aZPnh_KF~hYKGHtcKGC*mpK70JpKD)eUuxU69okpg*V;GQPVHOm zJMDXIm-d79qxO@wTl-ntqy3`&s_oT&)AnhFIigo~dW)*?NwitLN$YdVyZ3TlFHnSTE5_^)kI&uh1*?D!p2-(QEZOyYUE&cHN;j=}x^_AEuw957*Dt&(qJ>FVI``R=rJc*9BeFN9Y&o7wIGQi}g|ZXnl-+ zi9S{zr;pbs=pDLCpQvA|Ptq^bC+k!6%k?YtEA^@RReGmBP4CjD>)pCrmvmWIbXC`M zUH9lcx}kgZtMy*JPw&@f=ri?M`fPoUK3AWo&)2Wf7wFgO3-#;t>-8J-8}*y?oAq1t zTlGcyZTf(IyMBkhSie(WqTi+8tuNJ=>C5#M`aSx+`hEIJ{eFFwzFJ?SuhrM->-7ip z2la>ahxHBmMtzh1i0;!j>x25E`eXXz`V;z-`cwMT`ZM~o`WF2;{dxTb{YCvH{bl_X z{Z;)n{dN5f{Z0KX{cZgn{ayV%eXIVy{(=6X{*nH%{)xU#|5X1>|6Kn<|5D$s@6f-} zzt+Feck18j-|64$yYwIQAN8N~-TKe^9{m^nSADPko4!x~UEi<&p&!r>>WB2h`k(p{ z{iuFS|4TovpU_Y0r}V$|A^o&|M*m0mdl*lMC)5+>3HL;JB0W(aiznI>o z(KEtxq30scNYBNdQJ&GBF`i32V?EH>Vl#;e9_#_Pr##+$}l#@og_#=FLQ##ZBf;{)SE<0Io^;}c_>@u~5d@wxGZ@ujid z*kOESd~JMV>@>bLzB9fzb{RhyKN>$7yN#cXJ;pD_uf|^EH)EgiyRqN+!#H3ZG!7Yu zjX#Ye#!=&#@t1MjIANSLP8ok2L&j<2jPZ}*_cGoPZ>TrS8}5zpMtY;X7H_mS#vAL6 z^TvA&^4#dkegUUaPmrTkI|ImU_#)<=zT! zrMJpk?XB_Fdh5LP-Ue@@*XCutoR|07y$)}a*XeEc4)dPl9qv8Xd!F}v?*-l#Z>zV> z+wK*-qIZP%LhnW1k=~2Fqr9WNW4xDm$9l(k$9pGuJG?IMMDL~EN#4u6lf6^CmwT`9 zUg@3cy~^8pwWBwDC@}&5h7OS9vJ-clx-xy+(25a}L)H^3pwYW`pV)Zv;`HTyCek<2 z&&2qAekRIAv{+hLm=050O76Himid`z*Tm()GK$uXt@hpJXX0EF%`$DVpNZezG2mws zUH6hQ%{S=xpQQDYw|Dscf4U~FL^+E*zL4?zfA#qWEVBmu{sS(T-+zi$I_TT%_aCJX z{zp4O@BTpyU+pLVp7Q(ua{cIMLaR4Zjkp-@dXQ)xA5qOkuYK)jBB=epNI_ag>-j3r zYQNDo(t6uT%lv=&-?W_QI-Qj6_y6vD-tXTc zL$uDh1t@JZV{y$9Xw8zN{OQS`+ z?^UX~sCGAbfLe$nUNafgy*MW8I&#PVtKWaztV160A2;v#-ae}>CT+xX>oElu zQ@!^lYM8WP$ZRcre8~4A(K-&3R%|C#ld3n-_w*-e4{K~ zQa{nRiJII@i@|?uNz_`*_Kvkn*DihF&W8sq>j%vC+`8_jbvK#Th{M}E?#D1;5^1AM zjW*YRn3|2IjXFTDMf;oqEu7x{owST@qxP94efMObohF|8|Df)l^bJF8bNmwR#p}ob zs3zw}U8e1omb2=+q^-2lk?O&D)B)0YhnZrky-f!VsdEe?`&K&IezTlNAF@TD=b18E zkg4><9e$?N=d*klxrqAmGVMz8%mM1^8S2Ji|G|LvCu6ylf^81?d(<`htVRam5bc$t zwD_CWK1v7Sf3#DiQ~ZCDekJW1oM$;vIAk9R8;BTs`ow{B>g-i?2z*Z9s(o~T(DwO{ zQ@6jKPdeZTeef7<>oIe3nr#bc*9YvLqD~w(=d<}Z)lQpzxR4p3ZQD!-$H_TlNYKU| zqT?dU_tbn^ZlyM(GfH8Rx-3) zmy>~F^=%+!ezh+UtFnDh1g1&$*$HD#jx;kuxh6hrA;I!kFis|%W=>o+bXj^IeMysu z#I^ z$1b5x!fM) z?$`7gGunPdV_%f3zKe_`-{wy0SjAK_!k(nV&K#*v(Bc>RJnfL6Hjx@3r_XMuUGS32 zWieTD*NL$76Jh0%1Kk0_`GFQD3GJapKqGGdO#Ax})2+Y+u)Go#pv-V4jD#B6@(9{F z=D>@hfhfwikrrh1Mv^haSZJ4o(^HEX=6#z-hR6>&+j7Ep%1HlmVCdyD*R~BrB%H`P@n<^eonNSz z3~m2zibl+j_M-y$hMOv)0bqc-`Xzj}L5IzLxyM9VTlbvuu-vy8h87 z`q)I%&@S?_LLMPw!|FdmAqY-BEtn8eDTh!i!-S1BCmLx1y^%_Xs(<6;b)?+9fRz8Z zI!JliU%&3wb(B@;&@}^@YvS5qdBU8m3z>y0EenY|{%2??B$wi7Y^K4Mbk@3{Heo&; zkUrYKn`od9`OfeEjUnV}4paXS4Vs5&_&n}2pPmxX%;0*I2H<1A^7i(sSu)1f6y{lw>35X%3wh2x;^*h6#Oe`GY1YuQR)MH7zHQ zGMx^=1oIIR!AN#DNHteLD>O$by<6(rJYX^Thfbm=aLXhOGd7Xb>YB7wAeamSlm%>Go;$eu;k;k9aCer40U_Oy1Pc%q5ZmdDOV$e&<@bIfG zX13?*@RI)Y4H~4}TumNe!YQ2$2BzZQzG`Z2Jkd5=s5Xh_D8%ruw6p*6KSW%i!S6Uz zKs6c|=-vHv-Lm-(0WI~|n?)rcIcX*syshVQDdD-3SCS!o#{bXbW&|d@ zLF+}+!CGKuT(qsGW=4%1TBOo;WYBu4z6}8_>sr4#rAfRXGmtfbY$G=>gRGs%nfZKcC-kZO8Bi=dD1 zrbClq&Z9a1Abp=S{U4%lV2_y;(_$}~iB#(&@qpg>eIYY%Hp%i1FljU^q{GPMKV*U{ z&T4PdOvh)gc4p92_*V-NM|_)SnA9|50g*?UC{mpc1scGJF`E6jE;*}R9!Q=JS8rZG zVEm^R%tco2|6?I@%M8m&=7Q5*k!GBD7V9adgof2v`YQ6x)fqIJrqf7}z1_8X{p$6B z#X%}9%wds4i-5M0jz*dt(IN}$nU{$X|4A}Zd=CVYm1H`$Gkj0cde2a81=UDWpF$l- zGz-!}OcIl2p+WjLnw;+pP^3AUqI_>sgP&6^jcSXL51NSq{j7naZw+X40YS2-i5Mj$ zn@Xc_W^TSSpdF_k#ha9E-c9VD0j6Vw@Gh)CvMQ@e|FtE*!%U4Bla(|Rw> z8_A$?(b-NjcKSB{GS{N!deO|j%{-45X5xE@0tK{tX;Mn+9jG3>nV9jvd^3&wR;-GM z*@gGy4&SW~@$+KE7Dd@PTjEE`;zTIcF+v!~O(N|4|Jn8qX15aK{rqe>EZ%yACkD0qj zv@iC#t{9+eAxe{GUyu<%7;tc|SzcqVX%=3ykn{!99%%O=+CMa8k^W3NtKCT2Z?4~6 zl==3%$}Nsa8uML`nu~Or@z7XCN}3_XZzpScvTh7nyPD2q!YmoI`Q#mMpl_81ADZpQ zQbsDInNkFu&LytP0?bul4xfZ{luX~Q9}!d4n>^!JY)X_HABPBIWcVL!|x+ce08#O z8%euQs;5HJhn^bf9=hs|MGISy$PlS)G}-Ctp{T$2M$%A$9n(XnkdE{h2#jVq+H zheq|AH(p2c!(%k3$)it@aeSCsNu%tw-?xNni>bDS_GpK>$ws$*NCNbeZ{0n#^pU{# zow*wSiVRKKsD++D$lGnECcauavd!hTImYS!gSlT995eoXG8o&E zPq(4WT@l||?J;uzkZi@D);AKkGEFco8A zveqqKcc-~x8rW#2W}|3O@?qzJgd%g&J#$v0TZ7fURo9rq^_sw-JyeaIRx^e!4VEOo zyt9u+YMK(0SJ+4b53O^`9ILd~j{4?OZ3@*sqDv1Nqs=`R*I3fu{#};VJ3l@de&Prn zr|ijx(#hN@^nVv1&TRVD5fxmsgIdS)ft)?sH>gn5Rgziu5DKUsB!l5#$MdwLPaLFp z`_Aq>?SW;QEz{MInaJ!mvpCwvKaz<_w24&PLK%aOMcN&HdTozyorO%FwKM{)A-zeb zPNtbAB173iwTG!joGdnn0d=>W?)Z=y`zTEt%_U7WNjmA<-w+rB85H6WlHoua_b)Ah z_UB%oZ@IDDSYl2bGn`H&OOso?HyAX;SPh!c(OE|AAMoAYPs``~&F5y*XV%O&pPY{X z=|4$}FHA1{&~+&d_q01>XuteG!?HQzexy4&rnVQ0KyxR;N0VVPU(KxuqD}}fSg9GG zX~jws9O*jwY0`tV7s|~Zq-M*^RX1I7H2NN*k%ioCFasY=*Xt<#m|GHcX1Y%AR+8mE zWmcN1)8|TD;aH0>dGuNleJHF*M#r5F0c$KLlx=fhU}FyY1%=SlqA_0Mdx@l)!wA+yg9G~d6Z72 zKYhyr+n(kQ?D2)nTto{xN&c;!HX~QHZ(zp2j6l}4-&|Puf*X4O(W1>@V(vb=T-VT@ zM>?C1P~u6X4<4h#FNLHW#HB~DfFjxxfpy&wo&A~U?!QfKAh75%!@0Rx4<@5rWNHa! z+HUT*Q_f28`R<`5-M*%enA_kcL#EQ*C8DhfuqfdWlUvQ-7o^i2$usn_>BrxQD36`h zd~}ZbR$XgG6_oQ$*f}QsndQit^mix|&3AB>CE?^i=gCM0xE&(+aMrzpva zw$UkSPS$Pa6s`7MN(VhjX14mwY4Z%#9-|CO9(<3CX!7#b(HA`~@EYGiK13?NYX(_* zZ7XR@ZRDNr(HxevdKi+w&2IWb(ohBdV{*6fu+dBelxeVfGP-~>k zrjazTt4mMkQ;n?T6FW%K{(suL@+d3HD_`Bf>jIjlfqu;*$YQJH$+#jhwn=c*#4QN; zs*z}j9v2LX7$kzMEhvHo$|j3IBM1uh8pOmn9Vc;2;v^&zmke!C7F%TBX_k6Ty{6{- z{qC&?`6F{?=A1c`ne&R%Utiv=uVU1sdU#<@nV7+VH4 zXWRtnEVo*`5%Wrggk9%IrSyB9w znh-9NWF=5uX&GdhPyTGt@C8rMU3%)Zr+~q9F`rA>8-uNcHZzE22B{fkHlVZdbd6?M z18D#xGoEFFwVH431#B-ABM7AlH%uHZqcoW@oHIxBHqE){uzCvN(4l?Fe9@$E4&jVB z3TiZolB&yW<{<~D^VO!dLS3$6sBx7lG%w5ht%nlUmbQyl;V?WuZ4aqGINDWr!FU>G z0%0uSJIW|FcxR=L$01!w3=*>;{M?54!$}BGA`6y=RXZYK>O+tQ%PmV}iENztt^p?a z=;VJpf)9*NSfrq82Z_0pSqUJ#=qqon`!DWKIc}?J%n}TD*NA^<-H6W5H%q{}$7tW_ zGn*lQSvVX^r$U#-4&!#oQlV3J*m>{~T~6ENzK#twAu)0uBM3W<(Aa7(v5SQ9gv^3@ zcZ_Dgk9nz;nttvQA#EZBiBwAGfbkMAXx+n)RqJ$xTBfe)>^vh7kCA#UMi6wDkPWO7 zXq*zsdG%Bq0VI&YgZaoakwp9eH_*(hUaQzach0)5SXtCQU9vjotkjW@pIE(|K%%`| z@kHWM+bV%8ZDO3Ui8vEp-M~QWm-HQfPRfvzeuF6HmALh zkU9L&^IitaAhjlH_u!%ur^l-oFKN9@LEe{?^m?-QI{`Kig;{HGr+g=?WgfYZC zWID0E_g)p+=c_PGk*{M}-QIMW2YPPV6!cBCw3U3e33JhB2@?&S*&v~x)eK{Q2-r@3 z#SB5Pt^EEE$gH&T5>d=&H9cwv17p3m#Qg;^_Li&Z*|1g!EdVU5|4OQ~p4XJn8IoSI zQZW>T8S$5yx{;RH$5aU!jOSs_YMD3D1pOtpu-2;`@kEqiHjte*Hg6Qt89t}@@2J9-m_ogbr zTM0iGNV-3g%exU_1p=$2bkgr(hDju7cci@c>y3uYV262P(sE;&CzTeFtG{wFbb1?Xhg3&D@^>`&@_z_zn`2)q?Ve z{+++X5Hhj7P^P{_j)e(o*o^|9>mbEPxHA~e%#;(eTzY*HSOT&ft2E?Hp*!(&B< z)0@-J#g&V7CHldr{Ws0XP+{V^w;;akh+f@9WE$uE3DJ@1RX7QVhPPB&Qy3|aLz@~m zQgzKi$9X(z3BG?xY6^OPTh<+-WZWU(oo2XfblMTZTgG z+zKCz*TQS*=nP_e$81LWGhuG-vG>O~r>=PPCIAJ=!Dt^Ce1qwgmBiFGcfJRKCJLn7%Z?Z ztjlrZMPi74%2-uF15#-&rmb}<)}p<0El>mVnND~$0VCZGXC@>bHPYoA6};OA_7Sm} zOUz*^@A_%9y`KiS1J)7~*;W}mm%3&qOBxT$LomfwKbFsXa6Z*E>iV zONYZ8CebEq9s-}F`iG1O?VvXm_H^@z!^6|&Ym%O4Jh5`;o;%TYxD!2DjYJa_+I3+# zlS}V?INs2~;UDRq;+#(q5~#%VK=OeRTqq+nAHEgm?}5qPB#AXjKUHZX;Rby2eQ%{v zYSUvylRj%05>G!}p6L;cP8XDC3IaEMVR`16Skd?S&X3A7ErQYh*79I$u%(v?%sZ#k zJL4m;pt-`$*X=@Qeaf%HYoD6nOeMU_BvdWzX81>MooPR&DVJ9>T-x_(wqq-&B_T*z zA&zo3xkBh?UBuigVwFp!A{jG^ zUxVk`8LwSn+%c>SNWFA*bWT+3>WEuCxjJ6aixFDBhAZPDwq;Rv$LfJ>k7;{PmK1w< zjPWwEjj}pAg`0JClnN=Y&tmPs8;ay(Q58e&{oGYCR^1mi(yj~H!C*L1@B8Q3+@ZPl~6 zq!&bO2f};8i>Q7@m0}6d)}mU8;am*9``tj3~rQF+GLZhyuW^MAk8^?#B%=s%f0 zXhgSh$Q7=e-aXw7p2+OJ*0hk_%^yKwpiZl-zq6P)u2 z&hfkW9sLGk0DFeQ0DH_g!R(HB7;V3Y)sH8Iro<{30g$3Q@K~DJvFN*` z5|S^Wg^>0_(o*EyiX~`!FToX7Ytp#HDtn!Lkeb)&6f5PaxwB*)xM7v+aBIjO)058I z^oIL}_;!2+)^}ah()O57kA8jh>t+HngG|T4t6qY3{SxIh;&#j=UWvraCO8W89wpmR z=PewIHZ>NPaQK{~M~ohU%R8F7H52vWsO3~eo^Gh!t5oeV(R-?!OKFH{w=J7e&0iT| zOwAs+B?i2dE+B~r{gaR>48;Q)4y7xYh`^&=1K+~5D_|vR@J_XczX>S#1IZRO0CmZNq)6V=Ro=pp8#hy{Jro!e$Q|GkR-Z< zo=S3zk?vB7mf}1n|Dm>fL@=C4`=!4Hy{VD-*Xjl2D-BTPQs@~oX6tMd0$!iC<9@%` zuO+8tU0i9+U&#y<+m)h<&6=*Jf3V)wK0eM@E3J`aOR+V#z8SB!Ossb3L)$?=TK+%9 z{>^->52NWyYyCs(QMpi}O!C!0t|+y`yMJ~_ufKf&+JjgN(87t;CI&f} ze3Ymq2^K1G?gQ_JGck$b8H-0Uh+c~^8yc9nJ>^xheOG2GiS}mXK$)DvpQf)FrkPI*npJI!2Q$D=F)dG20`BIGn#;c0eAS)#qD$OFw zF-y2wQq@wQNWC=4?jF;)wm@0=F9}F5JodBFnJnZO;_TLRy$3xkWfAgPG0b6jCm;x{ z0lwBI%uLsubw;R|CPZkgxC@e_uQ6T^&SZGi=k(glb+drOmk1ZcNfoC_ZVk-63FgL8 z#87W_o)g7?H00h3#+@4<{A;h6|BG}yzTAC<9`iCnBg+&ZVfH(Qh#ydjv-Mzfw{y6-tnRGXn1Pi-&lBrd$k9Nfv83kj5a z=b{&?Z6p$j@EsU?1ghVq(NhL@St#TEnZ>Y4EP2}B9RCI>Pe!AxSBRDdWMyfMkP#Z<{ zF--ZL-rKX8g+)L}(#|W4TWyHz6wuiz)CdxGZZQ4gs6wThp8!0NgJ!D4RIjYTC3rp zq?G#G6(ejrMmj${VWc}vgwYjKylH~ouW{V1{IZC+o?o_BL9eb{6+D{~u5g~z=Ol&S zY80BK5jC?VZJ}%TM*L^S5$8zM>f7-+G#Z=D;xGEX|4c(sJea&C{ZV-^xv|LD$-@nu z{rLprdjh3NNrEfTbBXNv5Z&i54Oz4$hdWAJ)2Vq)oM3-EG z>uf|nT|zoN-o1$n;fH2$)A#Jp+*9D*W=7+qN^9+~wZnc%tMq|+|2h(-FHNW+Fbk=s znz_tsMJ+Bjm-zsfC@3oOf7>v$w5J<AN9pG-qTie?h|~@otUPr@kB9 zak{r}q7?ID5N~>_p}N~g{vBs}2Y4xHeSOpPw85EaM!q^-1^s?Z2F{WC4HQ}YnCXJU zTzOzbgPb9)&cu>L%6%P*?QP>x?<6Z5y;ujXoY7W~D*FhC5VD*@sm4>#;$YZ<4l+w< zXtPjvmlQ&b=%AKaDp^Y@O7&iz%*5hkr3*18FQqMG!fn>8VAeByYs+#*3|nhPd(l-Q z>3N(2?6nqgf6VG;zcQP8XV&r;f#eR507|mwOlZbI_{t|tkWa!AT^%R6nA{C%v4TA1 z&69_3OKD6b@sfq+h8Mf?{b9yfYo^sIZ22{rw2;c#m9zQ8FVeWp%(j)*3}Wf-Pevsj8ieSrxnt>udwtTUP+AFWEzd`V9PA1eO78FWEIaHZUR=YIeS8%_EOWd>a5Y~qSpv;HBvnqoNKa@qbaykY=n7$ zT!k}SC4TG(T~2i1e(;ATz(aPF;?hjcuQ*qt8*A+Fyl0Uo2%Z%KCskU7NB}kp8{LT{ zeES)`>v3V4hkunM|7CF0*CR0Bp~Z2#aS%GWI?7Na`{Gn2 ziJW;F@En5`_)78{C7ggtRNF(lL2r#kdho=x-BxKm1M34{_BcaVf_`~fHI<)LQzD_R zrm4V~soA#tii#mH1?pJ~CYgXplDtr@qov@j!Cn7OpIExgUrf_B>Q&7#6B2Cj`m8{E zW`)iY*6Y=WD0Mn+bwZf(xl)xF{ga>E0tLng;FY$3H?x;BPFxWp4%cXeO^H2YJmb*_ zO-5pQ7C@>|;P;r6WcNeZx`ZX!!yvwge4wL+UZt-Q)V9#=268@=3)>PI6~ zEQIvdQugLNBuY=Yn$~2`5`sD{WLHOfS0#^5#CTN~q@J9W{3tgj6&^A`BE6-`YB!lz zyTUX|E%(w~p~p}YAsS^LTpN|{hV64`trsBT?r(YrF^0$*s9uVT4 z7JnTU;%h*2t!}jy^WoUlET^NloC!XeUq7>VFsJs;ZJ2Y_j0#a%{IV|7&rr)v80mxB z3a$7371AhRUzm0qeQUh`rD&>DR$`qaiu_n?+FlT+YL$)>b%W|S8SxQWR%j$g$_jxu z65}V2^CIuHS)fJ1h;;YXvt6RzLznC>4;`%{N-K?sbFM9{R&_idkQgk zLo_+*5@(pD@-QbmdR5OTCHkbOz8b1SV5lf5pk^#4fq+T^8z1Zw1@BRsYsOrB5mMeN zj9&KJ`f~^bAAJH?e@eaVnDgK$v^S5^;D$-bR#uT&T!o?kl!Qx?lrC|G=)jlgz?+UG z!&Pb`@hF{1H0}@?bgKl_^s?H*ttu4@)t33^52K81q4y-j{+ihXbJkp;4nuc0r0XCJ z6!b_c<1Fj(s3^lMwrO1B&+@abuGWd(c%dC(h!TBS#rf3K1bg)JT zXEk0bT9*J4&AO!S^Tv&z#1%LxT8Cuw>FRqz*Wh0B;Iany&?@crR@mvXU{1WxC(~mS z@HNg)`2EAlo0fJMnbL5GH!}p;CSfAY&wyx06Dc1{3CTg|#0RrPvx8Zqc?^%*+4G(z zl*u+Vm256os)qRMHSEIS2o+ome>Zppq}{N{h|ywa&5Y>Ca*B6|Xl}BtNSEx4?~t^Qk3SG$AQ@2S3v!)TcHd%8lH}_$r17%R-RoH zY&o3n7w`S)j?FR9gux@Sx=JluMHbs}RAPRu1>U{XOn|wr=vslXTga$YpDUSnr_bej zw68DF4W#nPY(r5yK-3x1PLWM9a0WTJjyvu-R^v|5n%uN?yHv)Ys*_xB+rHsQ--|Q- z`VKRxH4K>SZJ6@l)3j}C!TabMK_)=54YhHK5_Wkp0Mh2D&J4ejlevmL4DpwB1&s7bS9HG5V^WE!S=NAO;bQhgcd`|UNji?rodba4cCEDL zYE?)9m4d|aks$SCzaKUF~C2#U*UCR3;SMs1r z=SFfz>7Ceu>;bWff(~*3`C25+l|p}zD#u9svaUHApA#|zBB?!H^@R7jYZrY$sA1L2 z7_Hc1-JPdZrL|!Gg83BYy*vlI9yEZ+Z0TMK&4|M~KQMN?BB{=36Z#&E;Uj-Ue3b6t z30KoT|k#nzrFxWMivuGN+d$X+TsgUs!+lMeVQ+{(Ba1}=?l+|nF4cHFooMxWGnOfDS#`L zdBi}NC}VExZ&l~**UXw{2Q@}LXD;+FO`nSQIbIj*6AX^mWft{`o%>?rvZn42q!>>y z-F>W`k@ibdCaf$pY&sHa9_~he>~V0 zSZ;8WzoPtlH@K@0Q1lCVV&f3={QlSv(u?9-zKzLu5x(nMD2A_lQD}Ix++2s0%gV0g zDz!8n!<~@cQ4fS`l@?H{jsUkr5G~g^OOWsEbVKphEY0Q+tm|P`G@NQ|T$E=k z5Y(8!W(KE|x7+yTj9N;Z;AND#?7&)hWs;JqkBX1+))?e-HjI&6PPk84ATy{m>`d!E z{+;4-b7&5)|lBW=0i1na;tlvJ8aSu z=9u(|d%qogimw2t9TD3Z)ylA!C{Av)hAh%85A>^UkG?9^RHai1#Jk76fr=p?hq7)4 z@BFB28Nh_=3e|gi=l~myGnI6Mr&%=dGzlY}D6|?hG+d3y9CFl`5sX6pCPqlT>12Og2BC`VF z=*C2lW=a1FU6WC~jao>Rt`!6oyu+VxBBOB7xRHcI1^YLr-Xi^Bq`@kYQE^6vsfr+lJ(e*d~^%1 zdYJ5>MwZ@#=%Hz0__>MAj5D=b_i#CBf=9Ce`fD1i91H`5CrEip&~mNYy7*QwQu`hht>p) zaR^heDJv_vsVH$qHk@yrsFoPgyjYW!JT1C6YIX%n>R0H-e5Kr4K(``|RQPMU z+r3$QQ_-Rn&bpW7kdcp#fjsWrS|wX$$aZ`roRheNtujP90Q5daZ>Kgnle_7Ga%86F zryAOkpVCS^6I4Ybyh~&A$rj-sHGr{+bYYAAn9-xcfR4fUrRU#Nc5FZ(Z}cdn7j({V{RZqBc|4JN9+R(OI;=EyaX-OSjCfjiOttarUOZ_ZRfG*P<8Q-AphzFZsXo?B zCd$AHqJ_;!M4}(nEZUpcjPZl&A+&&dNvTyLH3h|t%}DfKjP~?W8XhE`ynEPc5^5RO zY~YiB#;;jwL<+Nvd}c@i+&F;0f!1^;T6=(Y`fRE4mpa@1mpe6>;R9bT@W| zjkA9|dlZZRM$<8tcHGiQnB2}J1wR{D+#zYLRLU+2Hu$$1wO8M_EU1mSPjjQ}Dcm0W zS=os@JdG!ALbN?wTb#k9SLrP!RX5gFXqb5>JO$~y&m#xoD8$stdBC-Q+V|EN;;H8N z0~p-(8=pMt+>SpW;0%62HrN-Nd&(IwmqR>P5$2ZJ9fpcztDg$7K(g0RJN_Yw4pyG+ zZ@cQ#ul&pE3X0N|rRCeE$DVp*6kVDT<424iMkF2}*>L8tW&xH6)pdYsOA1s9kJV;?eDD%>I<+f2&=7kXR*~oS#0%Cv>U%HL}PbJ zpe(JlUaXo6%Jz1E^k)?HZYi0Gjmj!6%o<&8kkAG_7>gqGbEGD^-Ja}>Z2L8JG$X$% zz1$6w=|%fp|H8}-GhM%X`i7k-UOO+nsq_lBNBXkq?gg34E^~ux(~I`Ge)CNEO!s)Y ze6Q~gEyb%SE-Wusg`Kt)0P_=(pG8y+P0fjLmH>N(}e76$q-IY`}z>31tQzuN- zg4;&f11ZH>YYlyxStQfuB@g4O(!HLm+<`XbjI5PX~|@wdBf-^|Tq80U`Mkvnon?#Lbg`$uqSI|^a3u@egg9@VYg z4*@VEMe1;JZzMU%=x-shj*wev`0&f?!TCRtHSYEB-F>7FOlUEM#9LM-dT#cw%9vv^ zgKmwb$ir!tN<DgLNP^nbXO1pk%{H()#~Sxkb{J8J19@mFQCPrJ(h zxqq4fWe-g=oP-L25gd<6nI@VSwb*`)6gIxhJ;O{~4E&1bOCC)vvZKKd;OW>)10GbT6B|1(FAbY5wCQC((HL7()g`0=_63WDRob^pgHVdkNtRC`eM zf1co$ey^mVN!+Z!Jo961Y(MgT{C@j}d-2QqU}4jKe5cToBi|~v3e3MetGW4?XSFi_ z&$HTD-A&umy4~SS`z`Y?&${0FN7LSD{^eQUG5_+co2~n-yjXp#-n2n1 zu<{D*0^7u)m)e(E`FSVIHU7qtSE|1~YxudZ=Raw6H}Cx@uZeY8UK682&z^s0-m}(~ z{QbS~NPaIXVSWagpAP1yi}~qnel9RS7nz?c%}-DB(*x)Kt$WCy7M{*uYxT?jvvo=S zd*=83=I2}H$2b4~v(?Ys!@%shy{vvsti1(rB+YWJEoNp|F|$_8D`tifGcz-@R;(2> zGt-K3#k^vs6^@u$x;n=`{*Ud?_PvfjA|oUFnVRmZn4amkYPvJSwB9C9w#F4QFVf8J z{+v9%vYiOuwE5g@R(n)Ssr^i4aGq3l&dz*7kh|5CKk_E1Zg>S$H(;lRCkhm0a)6dSP7%*mdSAwr08q|Uits{(EmMVJ;wK(I>A@ttMBh;8V!Tczqpt@MH^6lYGgIPSogf>e!1#+=;oBtW!8`Yx1ga>b)K6qw|a_V zswKUyrJzm!=4$0&=I~^TjfOai_B+C|`CB^h`05J@p4QZb`qE^Zks$UQ5 z7kG*;caNT(yI+s|vjyR##cLgeX78@=ayC1lTSyly2XR;SsxlK=$|?6I8e2AtU-_}L zeiV6`jRxO!dr+6yx4(x%zIG?+t5cxU$k^mxRejjysE_`dm*Mn+5-8nN@;c*W6MPDi zINH$UjoW^*T#J2TQ>KUr3?#2cQMoGbtF1n^Yv*v$P=k@C~% zRn;W;@eSbH8_p=UCf0PxjOw@^`G^uUB6EowF?X7g zNS!rAq`lA*yC)s2*Gx8GaZ8h@bs5L+N=@6|y&L$l+sb@eG&tz#Hb(8Ja--iAQ0{{h)olqGAq^z{i03p8Q8O zVH)g9r0Njo(8=Svu&o4cOc9ECY{Z7|1?!ZC1h4+CY1Xm19-)BC=$|W9*`>lL*KwF| zvt!FHs}jPmvtMPSCy`1|VH8rPui%qUXM#Kj$5i;8+cP`RLpSVGYj8%1zV-=i@Ip)T z?>)S)bZopF7XdRyM19v!<1Nd-Q!ZHjUWoW@qmggXB)9NqM^rSftX{EoFyf?QG?zJl zsH}!^7Jvbs5Ra*xiB^)qhMwTE9Kk7r*!Qz&69evqCYp&OuV1o!N3>y*Ekm2$j{v`0 zhd^J2Rj9h(xWFq4RY9XuIvdM6ORxOr&z}H^jeMX3DWF>ZySQ2#*PvdJi*r3;IUty! ziX+*gK})0r37vV0GO^vVnI!9?3~>-uCUY#ubV;H$ zd3K)sck<ANry2{dH1b z_D~5n*@+XmNQf=%r6VZp^5K%1CzmmAhb>5aHq-_6f)aaXqk?gTtjrZ7s<1HF*8M~xMBJcT zO&K{&XkZ-!U=in2VCu1*z?)edl!OK~UNp^viFf9it-!%>LVI4&G> z>cxjp3ZSoXP<5+xr1x9fgufv2!P{n_=o{M9at!C1AHvpOq;B!lMDT04k8H*tzK`I6 zarDo)Yzhua@&AcdM2!}TlqPAHnA5Q%GNSz`4hVG6ZEYU|MHA+VVcRUYF);O@%oM>sxE#qLV;nJoF%TiVT$zf> zIvrj-p%g0Qms6?|Y-|kEYdCz!vYGv^#s^m21!lpVUkPSY_OS$L=Jb#0Q#bH=j;x45 zBmgZEXuuiB;y#FOZ+8r4S5(;m?>*(uP}xrC78%rcw-;Ooj#jr8X1Csl1g+qmVdGem zBW3#MFQ`!Qv%!L-AY{-aUXa)RUr^pO3Jw*cmA?ssOW`5hfu2F7b~HKH`yObdY9@Gb^-*Ab?Cf>3-uLkL~q}$I?_BeUP2i#@ThjNQs5&koA^mE)(g^#_Q(#RJQzRbSm}w! zVwwTvXbUwb6ri3^EINo=o^mW$RLN=3K{GKHTSw&DcGDE*tx1QtGuC4JA^o)7A9`e1 zb`4rmOX3x&5;e(g zQzv>cm92%)T%1HO>_@O8NvtIzyz?!Di5sNNVpk$V2qb3zs=S=`cY-LAvuTQ99cTx$ z;tydh+8L3LgM0Jy6^vAxMW635Ou~0Wpj_B}ePnJg&cZInlNufTzZST3zD(!UWM>&e zd%&JCaOSx(awc&q;suE9-yg8&Au|)e5J7>)qj{fP2-%yh>RWqcG>W*}T|UIeIhMe0 zlY2YD;GCwuv`%h+fdW9EPHuDXctp{+-y6S3otkWw-~@v+YX#7>Q9Ywx(VR2y;svZ2 zyS)IvoCV34M%+UHko!vXi5iRQ`3H})i2MOr{le->*Yf*cB0vzYsCx7`&sh6z0LhA#; z7gWu8^b;<_gpAf|b`C+;{MVn;B3tQJ^Bwda+u0d=}(~y;M=em|lpnrvLZ~>*akL?2Vg5=*}o+B@HF9U-& z0X?q)AR!wdQI72ri`;X*Ao5txOS>i$J+BwtHIw{tY9=7(XH$0M_pTi4;kpJXMJ<0+ z&F7%&uhZzAwnx@=b@r(*$v`_|0{0Q+XW3GlY(KKp`~r!ynF_(m9^u~a5^3u=rI4~E z2GjT}HlACFkjX`Eonl5SL@L_%EhCY?r2f&Z!d^!DWjBzU1Zk0u9#j()YE)E<#?FqQ zk8&+zoCY{_DqP>Y?voJEuu zR)SvNh~h_hfR-ZEb5alai@4`QNaVVI;P*{jtFSAdw_p73yHEEOK~GL4%Wq`!(>&Mr=-hPH4XtNUD*9;#wL z4^{7~k%UPn;n%9mZiXj_R0geqIrlTPs>Ia zMHMx{Az&&C_!J$4;>G3@rXlC8sth*UT3Dr2bvC`XI4_1PpWA;n&T9e}xfj60kqBT~ zdVlryrEGSz*m@>1dnm|U3U_lbR?qYx!1$EQkr@#OIVM6P|VYUuYn#wyrVD{5yCqQE8#y%VOh^O z`4p32#!w{N)%eawMjjGGnRq)E%(#mSF_29Il9JHKvH?y7F2W=jLbzuwDSlTd@Q(4q zh4m24f!W0J{kMW_le4{I3yTpI^J&~=?uy?MR>Ate2s>b7pf@9Wp;ku$8esu20(fh% ztg&@QFo}r}Rh<>wZ{8}tjGu%D=NAwe#0;x)j zpcIq`quug9(S>T*j)XE^5+bB;Kemx1OENrEG<&%y+V!=7i)>!#ox;A>7V>nH7A;62 zx#IU{(BOvDXL;K8Xh}qmcsFA7qy}6D5sJvE*wI+J;Q3zYIO#<@<3TsV|>E=ezZW zKg=Qf20&0VksRA2&o;a~bs(Rc56`9$96_^I?M2qJrA3*;Tm+?jl6j_DIphG94p?$o;Y&LF776bcXz+t%$USM5B)! zSpm)txHY|Mtw_xll$9YybWKLkr(xx3VZK+jTo4k5Bq`e_Sz)Y~G(J$+f1+BUICnYL zV-`Fxw)&8-!2H7WcU(LBf;8aovCT{gG``3f;-2bpMC>=9PE5h2XY%)!)Tf_b*f47M zrqru_-aR((vti>Dgtu?goTyP@8T-^5FwVZ26@InY34Sqz?%|#@^l}}@7rr%3us$gB zgz*lOJ7s=V`q=2htv^Wjh}9iVw6`S3XIr)O^>+fmX!^lx-SRVy*_u+8-Sk5;_w3DC zQ`fp2 zQLa>DryeiC9uU_akh?BKYN)7?B6^V=dgJL{l!1hFxNmtLrw&9WQU*7T!;8v zPhnh7cWIDAoxKiWzi@bghOr=BWPUITkLEdJ*EjPOe#x#ySGBk~7Mc0!f3BzXUj zi7B4VZ7uc29o1PJVS)|3)9W7M^99Z6=7DtSk!4Afvr;sg?RjMxbrA6cFIv|~GeVIq z=Ul`HUqaXAh{aLX=8z&v#Y_M#BRahDyqn@y%1!2>I$^+Fm+Shasi7*~wPuL|oE^Fc z5+3b>>k50hmBeKo-FZhHMv$TDB(5>TICmfr z#N7507eeNAf(xum{bPnS8llbQBEbbB>4OAz4gr@ZxiU)9t1D=jaBj1X=n%3)7{ZAv zx#}{|CHWib0o(+v3aULJpL1p-78*2`j1a7S|B6|dXrM5fl!Q>E72ANZS1QaNJPV93 zHVJ(jwuo9Pm3xqbZ*a#l05pQgfvcLz;F55-v8+_q93%%c((jT~kYjf^dY4fTBGT0Z zc1LsUCkT_XH2F6Du)ouY*z1p94k7RX>Y$8Z%1~Tjm)iVy0~a9gNP`ig9J<=lAw-`cRcde5h9i1#>Jk$8nV@?7(j}ze-T7gQQ*q}tpd{kulp>UC)nr4 zCa5qL3|ay*H-TYA12ppIe|8!(Hj2)o&S?nd9jTVW2v(t1NJC zbAYnZi6fMMq@*ES15;v(>yR>XQu&Tdw}$H-|y%N5prsTK2&5=JJ?PqlOHdlAk3;b3Sv zRJ}#KRd`DlEI6Bp*rneg;V4^~zq=WQ;Lx077Y8)iyB0$SEWZE zAH3OxyeiNj(L`sn_eI=ZJ_Y5bh-9_&&L-c9r3wYlEsi$WgC*ioz>a zyiDO1#a|$Oiup3&r^J915xg7EMIRecxQlpI!bQ1>W*-$dpy?>@Lq8P-zgy5sE`XXk zSh~x4)%IBWD6E63|GjpQbGM?EvKw>j`$Z^*pQG+8aZ(v7=RjP+B7zwkD=TN_M22SC ziW`VGT@KbLT~9tvgRfOSI~WiECt9q=5@>flZ&1CQch;TE=w7~5((;>Ic;Yqo5} z@V#bEc%OJh9BTBa8IVl*EHGoQp%Vfp-$pKC(%6`4dP!x!f3Ihj`~ZWiTc9;oLdz@M zriP7KI#l7aqB$rX$G)c?#pA^%JETukv@7;!e{=ZPD{e!z*8Y}0asp<^>H-n3`bbfR zhTOa62$EkWN6Qdp2WqgPaPgu?Q@SwXy*FDjov;ZPs>_WzYTtDRy_^{epe2L8-(xek zxct`tis5SbM~Zwp@tUxNyq|3g&7sw z16-J|DsOso>_6rNuuY;Yn<^Ev_m$5?#TGhp!^b%iax2}inx#iPTp3l7UdDX()P}dc zhcQg?Wpk3erIMnVdg2WMno8(JY%6@P$#<1;otiseu0q6y;8!e5f>bI*LZqW(0CH78 z_HSdvm{Cs#q zODzr6Th?kbN^sp2#69zu8bruq1f<3-r=We_Xh6r(Ed8b&Xk))YZJXb9eedg1;`A|! z-f+Y;w77kz&FqnS|$9_1wNVCYc={ZAUutBx@?;YKHsQ zf{3)@7{15%HeEF;c>t2sSq>-L23~_8Ar;nHtzJAsipDY5a%l|1XiO{B#f*2U`xk+( zi-oH~EG^Tl_pz2F6ZI;h(Bw?2*nZTt*fi}wR;R#eK&Hs;jg7c5Ie z+`2c-8?rxiEEY=cyzjXdx7>3Jxj5Zb9FvUmHtS5?7w{xv#R&2|i=Vc`mfSCNk8y02ye%0gf823Z zPrQYt?#DDvpsYnYtKY?rboP{um}fIqs6jiA$ObDFFYDLa+AlnV8L7(M*nek!179FF z_E6dp9d~gQlwcnde?m%cgmy$qsb@)%#jH99@Q-4*gBy=}^j+IkHl=&*pMJa9*#x?8 zZe;o%W^=E^d{)0Pwt}-{Y?(kmr&yE7jf+oEFN!Y*q_0W^MM~rF7r4-#c`3TGjwiF9 ziLi#LXTKN>2f8Z&4vLBn5T%wp%S}YCad(~eyXR7VHT+^u`0AtzN}zIOnBDX+B1UeV z8n^kGg0-~#m(t-c^;+GZ#t*dmS6`wKuzyTSa^(q=s;=d@4{I)vx4mdBU7|hg>5MZk zHK?0us%aZ~14W5en$HVWrLGN@9~w-F9DD2s%_?1_;A!j=&Qv9wu^Y{SCUK@*1Oahs z>6(xP7j%;;?e?BiO*7~nv>c43&U_kf^8_`tlOk{u`|IkRmbqepxmWE*BdUuZa`boN z*Q37;8{*=@UzsdvHD``H3*<`W^?s|8>LxRd>@ly1_>d`BIu9-Zlf=<2=MvDxN}iJ( zc*hjj+ckOc5@mgVXt>W1@`xclDv&(o1L-gUng<_RDm2en*mn#;dt!1Fu*YR9k7ep~ zUS&-agkQJa&vUov$Fyn8Lq4k?a5O(*`^+!(h&`{|@%~DR_pcCWz8)*0t5yxsnEBYr zM~-e7E%Ensi*<9lsTo_r4z8J!e--==v(PDF_0ne@*2A}$!QnNr-O;ZGz0y=`<9T{H z+w4t$5=HIy{0(8F=`|2-No3#HXYu;89NHpZtB>wuJ0=~cmf8GXxY-(~%~q3**x(JI z9lfCGBW*ip=R2`>%dI{l`@5zU;9(d!7>jMmnpw@uUQuj}2)#_MxWarVDO@FoKW$Z~ z0!E+$Chqf&Q`W|ET?sY+>6xgohF?}z$S3v?UdS_1Ao9w^{F-p04R2nIZ^Q6$A@Y~@ z)XP%-&97JeS{q+-Q$;8{Zt3dwKDrrg78N|}zs@|Dc#x5Ry(7bA!YTRVJV+f4M*4sM za3(DJb8$Uj+f&U1H3xs>?}ascM|Cdu${D^#deDhu*Fj?w|8Da3p>%2ZRvY&L$^XLXufj_L>;ZW;Mo9RJHH@#!|I0ND z77k{1wtrs4sOoh0!4$g{=sf1^dT^V=2V3c~yid}_FA%mH=q4y2=_7X;Fc{WAMMZ%JIGLV-D|U#Sj~|lV|OvY?2Ip8464vi%ASA0GrWdBEz9ng7cEP;V17b& z!%#?H_E>ukkB)e|gXvf0&^fj4MfI2t%NCpJCrc!+XbyFM@1q{G^{EwFo?eSq}*`EcYq) zo&gEtt*QhPYSPSA?3d?U4#TQRBMBtz2H^|rj8I0y3})>ktkuxbevJIoon-hh#Xg`_ zzEGL@ewlH@Ba!BF+zBFJQ4}xSezrcRsUrkA<6)co7dAuM7hj&l z_GMhoj#au_2V0JpHAa^@5#vMpniu~Q-q;PxdJclqjJ_!aQ}c47vs0Tm=8SAxmzsCp zZo>Dd8ttl_KK3}Qg5@oMTlTZX_0M_qm@T=trZj*sb9Rob=@PRi60Id`w@b zQ=qI@Ty6ZAr@MTzm8NY3`t1&ZvYRh7KKEW9ti~zKQ4djOUEwV!2MpfXxHHRYx86|t zxF7x#)PT*84Y-pyP3>Uj`)>^ccWI}76KA3&#o-Sgv_!vfr`pfVo;x0WZh7e5_1Dra zzu6e~e;DG|eSKaS&;2>16=U90@|l`U!Au!ifB!?DLBYU@e~u&NxXQGr@(DNLt;THM zu_{G_2F~@Pa^a(#H7|iz>Kq=DB(xK+Rs>h!YXJ({aym|!;)vN57l(>Dv$=1#1Mb{c zk+d_yKM&4s)EHySHnFD8Ut?qTSxVmE46$_YK3+fG-Ita=GNIp>a#2*@_XmVN4s(e~ z*fe0^;39c9fN6$zKk-*RtlP!RW2a5+-f05IN`uRMDAQ6&ewF8!4u$Bj8olXyd1&GA zy1#Bd@@n2KPmu$19%YO?*i}Zqcy-2;>@|j}OolnPJLE8bM;tMO&sR^QqerpButQIQ z84rbq$h}Oflk(8?ka-k*)LEuHMR9|N4k6je&8y2x%iGJV$_vW7&ig9VEJOv_43Uk= zMsgHH%x>YNXg+hB=P9%VweiK}v-oqKn$SrQA(9u%(No@1&?f9N*U@;MeXt+gDz*#t z(ZzP2fx3f_gO!7ugQ0`ic4F}UwqqZ9FcZRJP$`5vBk3fE zp|Wso^aDu8Fvm#g*iIrN)g)0O=kRUc_VVLnNTx$NF|N%T4C#7ekXQ!vCqOM}8;;9liO=6}vJ*``; zi|W6vyRWk}Wc_szu1n-5v#e|Q5LOMlhH`JQJZH!h)`fbnw_IwdAMQ(Z@4Rep=pRM^ ziwqkFr+_dGGmXrI_>FNL-A~v<!1Ff5nI&$1PB6Lk|^fXYYcQEsOtoC#4MwVT6- z`1R`2{FgqgKkw_WONO1bU;YSN=m8>}aItJq=|OCR=uUBdsLZ@T zFVc$@_*OPu@KgK^LV`-nT)d-jyg))?Ni-K{^E=0;Z^+ zg{9&T;?ptRlwO9n1i#%SYNP#_y_lcB9~~Cx$83IiQ@X|ey(M}Py@~J3{Ok~of{u!g zorsr+u7aV0t3secDdGI4`+_>HNU`Pku*?D3%jr}XW5n+rc%|Ueg&<1mAf@jCvn;s?h5O`);q_z0e;K};q?>8iy>dM2eox~$BtdU zm=`iTase&@76B3gegUR#azE8h41XUV!-1ATeKh+aebg<2Z@k@1??aDkyQu?A zasI@c*dH3NC6B3pwjw`>-)|mmuXuOehlwJHB0s1|=t(F^xJl^piSzjkWrc0~rC=Fg z%_(FhTZx6_(z0gKnfVR%`kP@nsn*l$=nd8S+e5<9bEG_Ib|ym}&;?|cGcHB?nP6Yg z-=(=Sa58YR(~{ECkL2lPzGQ18dKeiw@1}o0q>z{GWLA>N`mvnMMRrv&aDw)Nj!m(d z*vjMRyG!<6fucM9(QCKkdoHS@1J}xlO6;WGIPMPT!OO$vLYg9)TASvZvYHB-lq}gTsY=*Ov(w%5R*Ra(XHT2T zExRn8=W3+1)7&IhH!SJq2xakQy-Cm7n$+hwN_~^=#a1~jdFSp+2xNJ)7>gu|hKox} z4vVmh)l1Y%mr8Sg)D-1rZ)W%@wdZW+2r&4XJ-^ohLd278-YCWs5`;a|uI7=97tQnNK zxXF+SrCEuonRz>_3=19Wu!$E7K8wPX%@iO1&FKVe`k}dAR=MeFy1I${cvcQK)eUgs zgazAdGsRQ=pkYES{e*>R%7^9VX<~_GYxI@tW_-e))qiX~)sy<>qAHJG9pD4d0@wi@ z0ct5}3-PX2iZ zpISFyn{6fdy5EnTLN`J;=8pI=zAT(ht`M2}C%nnsPn~wHKsO>E!f>Nz_D>^J_zdMIfpX{TyuWG8OtXJ>it*p{=7?v&{?J;KlV@VYMJT)iHqjcPNngB7MHrMs#2|x{>o@e4ewu1lieyq2Fzycyb;o9JLx7|;B%l*~zXQPFvF{d|M9zmeF&WAD33=BcpX760J1+2NVH z=bQYXyIIqzfAc_~mFDmD&i!Qjl)9Jsq`v2VI6ZYS z-t+b2=PSk2_zls>!~VCF9-5E+*Ou#VBOiSJ+V8Qi8&A;J;nyFI;cdq2qv!PQfgS7o zL%JsdqZ_*da&FW1K$aWjg14Dimju`T)7Pl!iTeC z(9m(v?|Xwp#-VNntDll$K{qkQqvrrEjYfrAt?yRbwgKtN3vu{Vao( zyspyFZsI#iMxl`0sd()*+Ch<<J;M{U040>&smD%aTy}&yJP`Cd-?7DY>V_a>bFi8?c>kc)BPW8OCv1I%+y5d=-GUo3f_Nil!<07$ddHIAyA9iX2m>x|{9Fq^Wxf z1D&?o&zjSn2CDHKChzLg?1s4UZu*y>r=<%skp*=wUln=#s znWy*bp0PMU2tZVwT+IZ~N;gI;u0F4trSV(G(QMEYGm)0DvW~6}Be`-!zt z-7@x#E>1O6RZNWnV5+*Wo(v#R-!JFMuP6sbS2$Nr)wVZ{RRGI?##a7RU_ZEHd|wHk+se$$4b9hS6^J8nT@mYn?2D_J&qu% z0xvm2+Uhi8eZf*UKi_IG`nW5lPll~bVj-XcRSmtuOqHR`L=~>KA`pPsWR<5TQ^r?j zrMOT~k@y=D9#bBy7SCg$w-QQ^{jwsE3QPea2Zj&TgY;5#`+G0?iK3wo>CnHUQoV^F z>dL{xiAOF4z{%e3{ACTHFVA z@Gjh=$+R6aYU{9uf4Cv$OoHsRDzoUHxNkP%-?Rgkz&f$En?Y(JJs5heLG|D-wf-|Q z*&gjp45R{AfXYGO!}Vaf{7(R5o2FMKpcF&_GzW|iQV=cx1B3=d8KekA5;Pu+I28Q* zaaFmp45jA0A4;IeIr<@o*gH>R9)76*8V*`* ztAT%>6PK@~d_6GJO#L@e{}xt9Ih>HLx5KnB_W$RQI{)VKoV2q8MuM?FA`#tj@2vzS{L%pv$Jk#Ob$Mij z7+?jW3Qqj!f-0aJqJX_KH>d@&00uLq6T*tUGa<(1jQWqz!x6PcJLCjwr(LYo?w`VX zq>7Wg_J46*HQ>SoUWinT{okYRK!VV*PXZN@L%dwN31KczjrdWvSHwKrP;+!c%(3xj zPN1l*16a5`P?7X(0^}b(>p{o1x5fUx9TJSa^S7`bwPNQ`?9uaYO+u!`WrfI8ISXuWafBeqA`BoLbd_L{{=TrK>sL{t3VUHkWg@IgBHPa} zQ}ovo<35zpGeFD2+@^Dt8hA1G=~B{hc4G7Su?la~@%+@xdu0V=a&%;z9+-%v0Sqhx zNgxS1a|lFOd@l+bj_`j4M-a*PpwOJaVcP;j)&mn6&!_99n|g8(K7@}reWfZa*v5yH-s1^y4v2@V#4JTQ=)IUWM) zN3S3njwBeklmYQS!FXfIk+0-?IA|79U<^`u6tGR?fhpuOKOnSze7{FQxs3_iNlKy?FUW*;BnH+cnTHK~OS-_@0*-|n91<-AHZF;X zLpdT2_HRQef+7xZCf~#Q?7eU#$v^e!@1uzU`FqF8>)*4=7fo!PT0*0B!LX&aNnv%! z1Ea_t5+E3V^opUiO8(DqzDU;k5X?dn3{fhN1eT3FFpPYU5zPr3wun41i9G%Xgz^tT zX*5YGFdC`LJv6>H2nEKzM47)1BMUR8Gt5slChhEN3C9a$B+AN>V2lL0+(yw+tiXhA z1KLb&Q+n;8^H$Ln)d^;l|8As&Cl-1BMt?JHBf&VFqZAxPYAB3I z&`@Q;d<;cuNDS#fP#MrkWx+;_8G1;ze+jAbR?ufoVJ+?<*u23q;$k-bZ7WvJG|$oY zpG-Fo-xc(>9mGo)q>C}H?w?H{uTFru<~iWtFD)$K;6Is}2aUpHJt)!KE{H003ik^> z3RskV6$T0)Xg($JJXA<~fFcnJ9>{UkJ`e~ZnAfuqc&Ldu3@mr8z*B85n{l3rfM(kT zjqwm9Bm8?P zTR|-ky=&gvXZ-)*(3_j!_7{PFfrBT0eHwV`Md0{DZ?*UKBL4_6-+yHcQ_htST&2G` zZP-2Q7WVo8iO?%y|9ktg4=Ul=t3>FK1pQAT-ySIPf`NKDREIQs#F2GHwmvCsEOBE* zlNWua2|!haM43csC%+&pQi~Q?R#sXN7%5JhQD#w65DJ$LH%pZ$kbXN_q(JG*a-1lY zEBkEnSEw{zAoP}|NP)x`?pQ@KSNNHWTb)d_LOf!C7Bx9!EVu$njiG`^^{xz0k-fml zg`?0)h@w#0V*#R*a-01hzy5mYml**|e}ND>&9>RWYjHg$d#$1LST8dIm;M6%U#JPK zfd5WO{EM{shm!DEf2`1MMXmpvR-mmZF2-AGm8zE(4t?=(oA?|`YZqS2&1sq%L)jP8 zP8kM5iz`9+X>d(QQ$p$+!F1>`KE&MUkQK73cV5O}V3lyK^~?$0_5w&Pl*iw$ z?0SfoRsrhZoqt1RP=f3r6_COVC{}@r@F7~n^I-XZmv^B+t+JXy#lKUYvYKGv-`o_> zI+C_!V0BY3K+AxDp)M9nLju045OVQ1*oj4;>&SX|!{61g@V<~*a0QkcL4}tp;%7hq zp?9v%#};~j{rFK|WI|7aDcVPNpz69o5ie0i@_4c3N#4W{+x^vn;05{|7Dn zpTuz>6{rGO4g?>p2ihh1_NOim_)p*vGzZ#)aJ#S71Sb{Y&ksW#mS~wU$5CcR+#!lz z{||5vZ@X{EWH}81KhZi6S|!oYibYl~tbCN29k+z?*Stwuh7LTRMixR;qM;)Ty?of< zXmf8RIN_;6*xP8`w>BgXW|2?l`pNVNE)5Et2rhvE>d>7$+Y6wzgdTUjmC$>#!OhEQThU?faJ$XNPOad#r39Yn>sNXfn= zp#Cd%Dl9}d7W{YUzi9a%@Q#sbs|GG3;9qvP<6z3AgNvjd_AB}C;fiDHe|OaXu&;k~ z=KmMm@F}=G;4U$?uXOUXK%Hp}7$GN$1KKc{Q^5|Ddv)N_WImxW0Ygk#h9djlzw*0X zfPe6RG2#FahOWK{y;qP;eRpVn~FdfItl9crYksL4G(ciE_uJ{9FTE zNczG6Q;fQ3uoR_U7B~%Y&~fVjJ@gO*{Y)8y3E5c?ppJ1F38tsiO9%JQFv$xVlnm^@ zZ}a)a*?&9zw!c7T6$UtCIK+ZYDfM!H_8at&`hSLk9B?DzpexkG_>d-r0X7)%F<=c! ze*yom2K^s~LW}_!QV^hsff5NOtRzSc2O|cWPyOFQ#RxDsB|#FnRuNEl>TRUK9VEz# z`s@N~#cDzJEn~D{Coe-a_P@B8SP3sge`;#*qRWbZOyE%}0u>QMtf(six5oqofQuuV zK!5EKg{Y%~2*yZ7;$3-EU-aLcpDtfsbW8MB?$Z_f-D)&0R@j|qaCCI|UMK0fw<+z^ z*p<~1iWQH@d{0HRtDZ9v27lqM>1wQWzh{er^=etS!kcbI8xY@}7TQQPGG=vkMR#IQ}v zf~8Bk?5OHw+U%xfeON~MF+oa4>G*kexvREaCW-vXIZG-2S$5(^*XcO`%FH@!;m^4R zXVny;o40+cx7(77yLVhiqcx@dfL*$o>%)|r`^x!Twc8wUruuvo(9%)t-R?N3S{?q! zwH;sKk4VW^A#HW{X=*>K3XV+66W5b@y4zkBiMG-QMa!QLvL`cUiCoR&HZ5z}iQ*F2 zcj0$!E!roi_0{Kg_s(YC7fCh8U7f~@RhBj!UhAwKYu?_P&`p-I4+zzNJ~ov&JU@oX zs!E3!nNw1Kbo@Rw>dNNoC|$}}{UZ=OY5UMrW9KF9froy{MhTHKRPX;Ac<@oA27}bD z1oP*E*)@_FCP6rxIc`Bt*lwo!_L~q)U%v?;^HUciWfCkk{2Gq+bJLlM?SLdX;sAUb zL3&p2vRiw7`5Hw)x8g{|OK32x#u6=GF<7?*FFZ8yxakruvB&UQ zk3`KQiZBR;v~zOmtms2YI3nMllOPKNgM7mL&<-sm9)ma?p~X?p6Xahn7$e;-6qnbuh$Y|TZ|u7uQ%5W``-XXs`GJp z?m7dGHDBF5o%oFTysi4JfYx|cv9;X!2Ll<2R`NC6#Rn4^jd)mDTsKJ*l6e^G=~C8L1X=%S3fE|!btrK#}(`aa zlr2D8Ra0$#Zhmfob)I#hao!QQ0`$21a;J00=NiPLWUJO?mFd;ZBh@9?rPw9erO_qY zrP?K{rY5(bCc>^J)4VVW#Aw#-(&-XDQ!K5>wo2uZ>ry@gc+cy(w)2Q&mrp61S31wP z0r~D|UAw)SS4$ZcYn5u%YE^30?G^1+?Uk`BI4j?P48UrjE$|FT0L%uG-Z8q?w~Ojl zY*sU>Tqs?rU8tm1(#ekO6=5olzP;9RC?6?72V6eReXM;^SZ!k zAQRBeHLhKKqx8Mvz2saSxvZxWdO-w81k45M1LJwB2mv1eiFq=h(jC!4Ev!~NR#m7) zzE&DmjhF=^gL2etK{E~mAZl*68G=DcX7)!j27{W++-x%fgUa}9L-Q8~_3^oD_7*@M zrj?jhJ)j`j%2cZjkgsN?wn}}*W!uCdj$f%}T|j9`SS?<;0BrKA7UI?872;LmmEzUp z72{R2p3i79s}@US7vq)V)#Vl8RpFJvFU_uwS(^GiwJM!5uLQ4ZuRO1AuQ0D-ue6r$o%)bf zmwA_EmqnM=i@A#>Vta4oBTARN`%0y~JibN_zN=2$gik%nom-83%S54+jmP{5*R!rti zmQ5B-R(IxhmUb3)R(KsR?JgZI?Jpgv?5G^5?5P|J>!2BB9lWf0?{OaSAcE9}m+Rpp8-QU?3;_mUgwb&LX@6o$8Y8T|dqu}Cu4yazY z0g0!=;|Y&nwMqFZ1Pgi%MT5pb6`9Y803slrC!8YjC+paD(KG$UwtTsg34T0zJbeUD-V;F;1Jip9Op8Ia zVuiKKR7rN_n`#PG^i$Y5y}N+fa${oV7{>TFc}y< z%o;`n(}wZDJYiTc6&MT5Ij|9)2(N+X!+YQ%@FI8$ydE9{uYhO6+k0dXk_ZiiBEkUl z2e8-*0iA$OL0}L>>_q5}>OK#u24#iW!bk#Jd*ncsmy5y6!HbU&lsnLU7?cKv15<;s z1QbWl9lZ+OxLA2Qt-Dz9Yxce*K5K3dF7JbP)d+0Ycb&!pqB zu_+EEq+r>|6niVub=kxe#{<&m$jvY8=n1sNYhO4N6F9?$g=9ZZpxn#*L-Rmuy=$Y2Hzp&*mdng8qn;Wg^FFmaUQX6kiQ5H2(bv&q(u#=g9pC z)=0vL%82B?O);o#xNW&@x^25{ux(M#YRmc?Z^lQZgw6!(5s{JZk-!mm%ZT~~J?kpo zm5-0)I3FDoP!c>x{4B$+lXtm3#7pd(@8j*OTNYnuUAJ9_Uzc3}yl%RVuOIhW@tN`2 z@#*)O_ZjzD_ZjwC_L=tC_8Ih9^qKV8TyyHO>~j1^zXSxB1=s~x1vmv*1ULlP1h_bH z^sx7E_i*;`wvcVcpZ`P8w2pX>JdWUuVDHOWmS3mUPd=?b4X-($aXgT{#G597;$b65 z``-J7Zeve_Pm52JA2}lv21h_6(QZTh4zHF^D*c$8Vbi!=OPE}P)2NHqvOsm4CQ{20 zpqouswiyFZ!KNYGq6}zn(~)g%1Jt)^$+kQK`r7n>c`>FW8^^x!DotrLPJQEJo>FX_ zps=R2P2?TTvYd9%@T~ z{}kM|K-=v7smAH+BY~s#Bi|!rk6-H!e$%|S0UoKoA-+YvDgSB$F}@YP*%d%wMNXuB z!`TooV~*yO*RA_4dgEZOgBQ^Fi2GKtar2DBe;Ry*=}{&ynd>~maSXhjs+@X0TDB=@ z@9P@rTIrhU+Ue@=n(rDnvfFWb$Z5^`_qIE`HOD*48yGj$IW>HQ?@{5~+CJ4a+O^s> zYvfYHt_!T3T0SDX4Z210sD3VNpD_Zsuv2jc9{nd^C+Z|>A?o15O~pmUSHNDtUBFqu zTfo7WJqw)8p3Py)Vgs^ev*pxg)dFj?YjXfu03aY6kdrg*J>@<9IQ2MCNh#7CAEU zD0r@X&S?h;o55WuxpA_Cvx0%a*-}S!zH6_W6dXxea?`=ez4Uq#I(0-A5eDWuZA9kn zRr1Ueu`L!=ddxGit@u^a%;SnJ8dX}%(~7N}Rm#kh6D{slM$EGlw!Ru6+IB?x!#XkA z4(a-bIuY9T+WN&+`&IKRA04Z-ontbre5=SRSN=4fR)2u_K#(EQkk1e+2q8qPa^9f< zSWT?dLI~l8{D5FWlp)_7b3I#lb_7QSR|RK*W-3hvEVauvc>t9L);iWE)&|xV)_T@v z)n5X3C}&eMmLdid4odS>1=~sA{u2+zMA5f(%R!UA!2Y`jmruer~^@3{}T zFS<{;ufLDEuei^?Z*Lxk4nP;66VQzf2j|8XLy#WG0HhBx6w?!`qN>hYQCne!*g{Ag zTboBW9M2nrnu8i23{k2;)nO|%5FCgagw1h`tOeUJ*pO}o5Aypy>9F;^&=_`$)Y*5T zDeP7{r_4|Ga_jS6@t+(=*RQ=o^XwSc$Gu|n9Lm?hUXgkB{}5PSiFuC4>(4EltaTXY zw4H0L^-AZQom(|^%;#VIe+K>&I8$0CHCH;%XE-GpTdr<+dUbD`Q2`3f{^bX&0;d9t z0tdbg6|cr^i^&#?0-FMt0`q^V!aAvOwq$c_N#^O2YgR*~y z$Y#FfZ1eHD?)vR{<+-STNMJ%>bzoj#cVJjxabQ~aT+jMNE1(|G3}^(jUe;YUk*s^K z$DPwZXuP=iX9p$))&>@IZ<(0aHtDWcp7T7w9^O3|yh!-xb?@w$iCMjzA^Fb*tpyDQ zE$!He*@(G_nTy$rS&KP~SppggnhP2WT21Rrn@k%_TTJUsn@t-{TS0Z8CQt*Yg>Un6 z?Q-LC{c@9PjcS8xoocgStze^Iy#q98(~4er#cJKyFJ)iAEq3foc>ZM2lHLM^f_e6oG&Fxi>gzb+Tjv zsW-R)(8osjl9YO|dGdI9Nw7ww^MvEKNr~|@_yH~H1vV%OBGAIFyNO3)Ss2l>GH z1Tt`_+Qf@DqvASPh2;~Nh?lzqO0-STPYCV3yQH&k+9i<;ct_@0b=DBXOYejV536#7 zCuqG&KQ4wNm+)!~1c^3Bl>POsT^*)+ZIz;_kfJHwg=K)mq^Em}_xL(&8Ho~yI$(6u zkD@y)8V^x`zI%&s)9A7a3?j)_$ty&w-1J3vi^IhD zX&;Ci&F8|BN+u<^<5HH6OckiBSwrvryS>|Iu#(8L5qopx6;f(>>^FogprZI9kmfq_ ztMn&4yJ#VKnnhRNLd;t~A!2XVi#rTA?rgC~v`U*AV0%!1F)Zn!*0doO)=xxJ{Ex=g zFVpQG{BCFh-LP0HmuouKFzOMh-Pz#H@ ztHGB4Co2Hn&J((v6y-ZTz69eL!SrI_cr96alZ`NVZ@}wC90izK|AwX|>oxcZVIv49 z+&jkO7P0>!pRI7%l)a?l<;9jKvWKvbgp`qTW3w^CdXRpeH6%+|+NAXWlnljKGG%H` zb2RNM;)Tbchva&rM>GDreqYz|XUa%1i;jURVuNE14FR($ONtAHjXs=U+n>0veW@s8 z#A60!)mFSc=Hc`u`EB`+U{uTndv zDV1&Lsg~Y|9E2bgHNKI5%A9MA8q5I6)OGdw$muW)J(|F7l@OmH*TvSmHoK)25kP&fqJ*=dCu{%=QYmWJy(f-maaQ$A{-0huzt7n znrpc*tc)Xa^)CJ0EonUB>Q!J0CB^yzLg12nK}M`9ViE2kc1_5|3yh<6ubjX8;%=Y+ zDdrzx8;!HoN4HA9KJp7_Qej!27)^_Rp}UD}z4}_q>dG*Xjh!BD-l7rkD0D4PTYb(A z+F!a*NX=oUGg9 zWy_m>%s}ud? zS!4(dzT{(XE`p*)e|{2;Ns*qM>~Sw_-I9TEE-shOgsf0czAU5bR5%gLoEe(ui(NLu z=(Bn8m!3-kv7e}$R9L`~3l10@EpgGA>tK|XPU8n9S}w3yRf_s8IgK~^g0>KA%Tu|~ z@ceWU=JJ~>E6(X*mrHsl)`t`X*{(;w&Kt|V{(lX#SS&v!N04@)6KgoJ?beHZ(3o}o zvob$}@#u(J*w!)q(I$k&b2&0?_EB_ds!px2FfxFYnF%#^d(T=c<1=!#fkehs7JWkG zZ2q;N-=BkkkFyQs6CarhLW|frk7+O8V|yH49}-yI(A3LllK!pRjX`;fuVPHb=zWo5 zRu@(iEE6e5+&;V6(PUd8Wn*4)A$P&pbDMbH8%p~g{qgrxx$ZHl;3%B3^CcYI zSk5)EAtU%CxwY%u$?zSY(XDqZ09Xs+$@X6LM-k`@p$~B<8GbszZ)>&4_xYQ3Ko=}k zW(v04)lLK?XG+U71#Aa+RhZF)LHywqhHU0)36xhlz-i^n=R7SxAwEGHz7@G~iCBPs z?>@|zI_JPYrpu39flmP6aQoX#0s;EC$MZ!|Dn0gmuH3kOdmBn2a+net9M1;x2T%4f zRmBd5G0f4$O6(=vF|+Y_DwK7_jzor~=}zD!EiIPeG9Wo$stJ(IWkM2cL?|9npU(lN zPu&=MJBBD(y^WZwjQM%jH{G*}X&Mhu4+W0}L<=A(wE)qehiNeZcJLlVe zYt$kq*Jmq{gJpnT?|*xPVqeO}i-gt$Ma2y?qPriU7t~B9U(ksRAl5 z%N9l{Ko6oJ)d_6t3ndcwDxO9=*p$F0+4%`d>X=$Ln^hD$m2>neQiMya@uR!@K1NFQ zH1>#w7^+*II4P3Y@Bor0zzJOyx`7Hdw5~XT!pVE}a{pJn2sI^@gTO-J$f- z!9d!%%c_6doc0$5W2gD#cT_iGs=?=k`7cWs$4HkxsUPGWJoY$D8Hti9cQK;dv1eqrL|&4rPUSji!{<^}Z(3L+eW~!(&;u^r)SIJOHh;5V zYof8zSl$~~0**;F5q^}w1iEr*%LC;P#r`*0Lr}PFDd1WA9~bcO+Xie&l#H_CyheO{ zZ*tRrOjA>SigH))$mjR8d5@0$3ik6+@((PO3N4Q3iZ|zci27{I!o#4_mVUg&Cbk=fBO|>-Qua*lOX-aC?LEw zr-@>3or7DmNqHR?$I9#KOXAU!zfG3110C4j0@EOl`%{o$>tgH1@RTi)Z(+I<@A!`e z->hiVL;F<9&oQ12$!zaVT`B-{t!q(CP6tdX^caF*aIMFRIGMzm9Q#?g8zN=TPBi%8 zIpYTlxFd`l+q>NP8&A92MzisO#g;MQTuOQh+%&NDPNTgd6T}yHp)ZgG62QS;5K|tu z&BXxS=Br)gmvO}&9SXTm1`G$PN7iRHg|jWw zzyS&$49?VllfLcv&)vP+Wx<8CvA?gyF2>n9j9JFrR#MlpYp2pkOQn#XG3y00HlV9X zk+qOjBpf+bfjqCvCA>=P(;|#76Pi~N*Lf>lz}9CqBx4l2Z!W|WLo*Y5`+QO6{_gzo z`|p-v2)h-hGc|{O>EN$;DgIXMwrGUi;y*jw5$uVa@-W3RHOXnI_0{1*`}@p(U84Z( z`eur>D(C0<-01h3wp}5ds0KnnXR<63n)9ZwArGfIF;Sp2!$iV8oy)KEo?H9*Ml+kn zq@3xr&mxkT6D|Qc)pie8I*VbVv%c{FT1txq(4K0>jI)g;DN)eNCgEU%I#tqNz~2P% zY{~sfk&Ij)e%%E%R`n@HEzRAsf~Kpt_=dI-h6V+Z^r+T5I;(iAExVHg`;jA@>H%=8Fcg@)K$CA+(=R^U&AuQd8e0L^5s(AZL4_Gr%b|9A_*0Adv`az z2izIc@Fds1U6!v4O(*~_9r9WQspsh|z(<~eGd(K>lE3J%wB3a^`kaO~CFkd;6*MWp zsJ|Q22@!&u+JS~&-%|x3A~oNsRkkCnV3_ij_GK(TXiF1?TbV1yN5fFg`w^A#O;u+uFr?MlWxG`2W)FM!TqIa5& zQF)u5mj_&X zw+rui|3Smc2cyd*r(?q$xi6Ulpd$62-GV_{<0Dc^TCi~H+U>Uy6K1JTGXDNS$4WaU-}q>w(PD}9_>hRXy9S*A4p!(cn^z_kyk)6mjTOk)f; za+8@uw%X{LuOB&8gK<&`ycB1QbBThA$7Y#=J@@*vVXAF?v{)_wo#<kH$WZAH(o0%2L5i z0ygzw5ytF9ls{od%{8u5VDdZ2&mf0FcX_!b{-@!9M(r}*kJ zyq3F`1Z>N(7UU26{%ic8_fs6Fx(`vm?|C!M;$fP$-;Hf3tW4%fMK6&i&*kirI;zm` zSnVD~XUCY#h;x;@{rTAALg?Ut|vWZ=9Q*iApC zHl>#!M^)i7qvSa^_-u5VkN0=~l+wVI?77xOv<5WBqacR~Q`?<`%R@A3AFi-I04f_9 zA4t4L-?FI&m1}!PUnbW7jruaQEVta?Xuo1-=v0e{Ah+S{I3=*D(~IAFFs#!wsIt=j zrj9!Ri?Z>cD^MzPHj+6MAPg;4H{$*~XHDxk`nGm>Dh>yW5dRu^pq4QID-_^f4K^L# zuOSM_ic7-US~{vK`j|n{k85G4x|jHziTrgS&`?)n{D?EAgE(}ndpi4;5M;=DeD1cj zQKS@^ulA{78DUx9#s9j4lt^?7rW8N+eJISoaj#tO(dv-WJJZaKpECcJBsh zmJQy-A^UCLHa;>uB>zqmo70w913v<8doO=w)&|d`!?0ft!)9b*y$fnTJOKrBGa`Jv z+pm{GlRbT{<_yF8t+@U-A4Qf@zA#(^hDUDO?=pNy4%O+_gh^d99%f%f@IT+|-d*@5 zEvD#)xbuM$ud$SiUsFv`)Ytk;FDo2_309rUz2)h8BQMPxgRpY$(fx+|jPuFeh}2vP ziVuFwDR}%N#E>#RSHT(WqC7~k#EVvw!qz4qaa00AC~1PFx-l^*p3Rl%AKNvF!z__A zgDY>1C4J0hHBheu1C-sb0VF3x8k@?%)E8qq&B6U3a=63Oh}Pa8or&uY?HBxeMN;cCqmk{6Xn*A?^Q8=2E@ToPPuVB zdjyE@Tw~sgG*ymMX2vl%i-Csr*v9|;7Xs=8ZZ7*dgxoBfPsB(d`NLX~lU;u6vRm0G zT3|@K7HiI=X_$%9JVbk-IXl+b4gO{`$O08kq7K-QN;Cvcy7| zW92t{d??_369CttO^-A7A9x1-xk$DbD!hODbs7V>UR8A{WSbL6uK$cjh54|!QeEQy zUpi=R{TsXk{RPQ+W=A=ML`U2{an<+G=igNWUA<>OmgIGP&zn`haI-yw7)s(mQJVPD z#L*BJ%45=sMxNw}Wp~;877^vcp(uO6f7@v?w#+fHX%*J=4XO+YhiVZuEBF{1A690) ziCzA7n~0a%B029m6+W8Wbr^g(s_B<;oA4S{Dp@!zXg9r?fs}AIE&49rvY1!{>Wthr zqsX$2V|EWbh;IQLK3+!w$;slF_y_)A(XWA%0Mp&iD=~1kxA;79(q-`HZLJ;mRsyN- zUm1tcTxQrF|FceRv30p-ePHow;R8Dsz-{eBnVB4ZwK7UFiIma61=CvWKcU57Mtmlu zE=@z(eNZhhsmf9;Syi-#Fyx40l6J-02G!uJQF+xoQFt}kmxLabE=h+O=DU4dmTk!qwrTirgB&SH zyyiGVePVL2Pl%!@c?Vp#;DKdQ@)CTk&(Wjm>Q^GcxE%x2kZmZAy8CSDyQNEHi!M{9>EnEuuC#L4 zjG@;>e$cKu8#rtUD1M1)VBhM%eg#(lj!|8x0vpQ~V9yx{dwqwtL5%77+0S_wq>}Yw z_i`>r#)cPuD;k7(f8^HDJL)}{VVMg*_+frxI(RVF>#79NoUrKEbCuT)(Yyiq1Fdt#z$sXpim zsd7X-XzjO9YZ^*U9tN1?59~Xa72J#k|1RBp1Ug!+v=rea4&@HoWmVbDj%^NdNC7Sd z{J_79oaHRqXg=Zf6fvI>23`yseo7!u6xv1IzbG@$xrm*g5kGTpZy#mBI$FPUv}!0g~KP#ZbV*Hv%M`Bi*Ao zqp)w45y#`weWGxk7`s+S^z{95{&_*fcLtg0lV8;b#m1_{%{eni{%l!;_FmZ2#>_hy zb2$reas2@?QHjl#LoL6Iv`DO(%3Z=D9}&c<<)R-Yp%4|Xj9;dhr0IY6B9g|%-b2Ev z*wEK`xE$W*HP=v260+iq$k|0U#J0v3Be|FHC?pKvDv(Z|DMa-}!+VX^M5)$Pv|Kzy zF3G3-x*M=g@fGDL8J&&lc&aAbxMT;?RcMXjsaSZRl)f{f;+3H2@sxEr@8Qh_B;Yu9 z?jJ5yL4<|d+Y@VK`WQ@>(!winr`6~)*aaw|YmrLJub%I)s`D){bavFf)yLFe3M#nJ z3q1Xc&?HOM~HE71qD6!h`M zz2vd%o1@2wNw^C7Fo`nV2Fn&bQrhhcnN)|fr<5>#p0}EB*-&+8820~j%LF3+SD-1u z0b@g-mJqx>r#?A!L1SX+l|O(tYGzs7<0<@_R=2vZ2Q3)ya-5SN%zEnO8qxG?*kd1B zBkdtp+|Q&BQ4My%ui9Ph_!H3ZQpab129ufyW*c6SvHh?F*bD{Lp6yGx z3tWYeO@FobSL1v-d6#gcS3>;p6hh+3_N>JqpX(8g{5)X_Jip4T@Z$(Jf#uZ1=4a@$ zK9Z9QxP3n{nfVI$zWOt*0rturtT=zy4{jTo$xZzNnc_cA3gpSLtlqsE{X&dM z9#7xl1-OoDgcm!f$=?Vb`}Bz3%;MGD%gXTu7k`?}!{;=D3NPRR2FSUgqL*J++=`O% zZ*pZqUXuvgFL{Y)rpbLhw4UY~2P-NZp}M!xzC@rm`iD+oSKeE@Kd%=f(Iz?(1zt5G z{C~bqgRtiUeM=;iqoTh2R$u2o6quu3W$J0sT!fa@(hlw4K|RKv1{UADf4y>J4MZ zN}T0#v4!nNFOdI?chBV`EXa2I^uKW$C;HIQ;r!0&Kmv{)O~I)C2?{Lz9$EzqZ!{To zA>%v~yoBD=KZ@1zU#2{pxe|*%BEPKCe`}W2Tb*~{T&Frl?YWB@T1(WkG{Ww%j*fRQ zF;l;M&mxy&$WyRm0{yDm717m>(Y%+U6PXuRIplYcdH{;^>LA@S_!Xx&#;gpF$aREznFp=MQ zUqTT5&OH}%>|rgx{yR2kW9D3r{09tbJFRc8j|-EcA^E~&fSgEG%ZMro<_a;=b%K?k z(VZkZ@4^GLj(~^%ekP?3xS&=QuGzS#S<5!(X?6cDzPoYJ&cd7vmX{0az81uhU@*BAdx-ajXJ&58j zYg%~O{B40%>^9)uDQgBm&x16^+NGu*}JYV(3an!QZ0!;PTU2D)TKRu8~jD}5=#A#Q`y!#o~*h$3n(ebDx z+_*UJFqSZ0c4e?Ks)*_PxWI}J`4OROgNfXKsam0zdRyk394qhF(?+1}j(VHHbsH^8+zmB( zrC=p1$R4Na1(|MrQY#?|N`cx*`kAY3Ri%w~j6OM{wkM$|rv2p9c_?59iE)Z;eT%iO zy9l%XaMYPPn)T>B`2a+Mp+6a|6TAP%Ugf=?YLvKtHsaZlTjJa0hru`?b#zol$)D>> zeY9hJF(S9Tl6dp!5HY1~pXm#eT_~#kvJ%m!T#{j<^DT#{xov^Mh6EcgPWKr+&~#X) z>nY|la9?iQz-)x5)mXPgJpx_k>+|oZnC1vt;DE*>0V}u`%*D2xAC7-caSpPWobmcxhs?wNZS!WJI3_;)<(fIK*Qy7@+GL{lZ``| z6y?Wi)z_rNR%689L3<|-RzyX&cmNXwrZ@jO2jj9h>A`QZVON;V>Yh&m)R zn%0yGRjfClzd094B~bw9ERP|t8Td}YZ^w8okoSMOP+v>>DPyWBTz;P4{N;%DjnX~( zd4SwVAeh&Z*nDMZ!pYY_URBQ1*^?#s`fH6o^FYsrfok;DKQr80vJ;Wv%o5W+q&BBW zd{3naircSiOerjm>b4uLNaFfn8|4C>2X9`aFpimJqj2yh^1jh{)esgxJKf(pzq|#8 z1Vi-3sHLyernp=Hetyw%ROc)2JPWLN^_{=Cm7q>I^D22cww{ z(M#&z(U`ik`qOWrJ+3RUYHRBydG=7!B^0NW&z~ES7$mODsx}gAyivrR`PTeYzaRhE z4GAagRWqh5NY218;zKO0F&XX9dtICkJo-Fj#IO+R%Uf;mF|MQ>G82g}C z9nL#GI(QJqvsYB?YUFsVjQ38gLWp&0Dfi94gy%Ct-B455TV3h`pm&f;>|9Blh0cAZ zJO@uR|HAsn!RE3Xy_WbE(RL02lJ<4kU(8yg!dWVblqt6ea$f^*?t%!i$sLP*C~rc- zTm5SuUEW`3p!XZ}Nd(3e#oh5pQ>bU)QaY8qIqGg3o0ixu`a!!ByOGpraGOQodSR-x z{_DSY-}P-!+9}vkiwCfgS|0rWR1fQE;r{aCprg+qLEF|cIVl?o{ZiIjm^N-;nE#gk zU8Fc;gwfk8l#HML8x$b}xK?YEE-W!+v9DN0^)`Uzw;U-wF100Sfq=9`{Md8B#yKWW z{o<6sS5;qGS#%7ehSj*M04<|wEkfPyz@tM+@!ak?YOT^`A9T4sJDX3byn{X-+{ zl7A=q6~6JNnG!~Cdu&>`zXIp{JzedClIsaYY-Wj++Wezy-z%*D{567PRm-mKb-(5{rm462`9()l!e@>O}KRoKbA&0;yBsyDcq%tjoj zWJARPVbLknO_YE}@A zluZ}h|5|H&?w33sy2w`Lv)!9iBbB4Y zjYaGjp7A-{x%RwK8@#`mmf@%Q_$Ao8{E#(>-eFW)vXvvDvU*X?;J>r0__PUbt*g`xpYfSwC zy0G`#U;o=MwlREAYK}xx%dkGg36q52UfO4+HJhPqR0>E6xomUm@eKfJ3zNq-zCmKd z)y)|;HD<1lpUGYX^}Xv~zx92lXg5n+xZKCL&WITRs6?QL3Q{-pQ{<8Pby=~qh2Q{v z6+p)#LcOtEbzifhO7_5K{))$cX>JFtu_+J!{OEIR(3AmpNRRij#p&#E&(!+B^*@U! znW_T0-tNt2>7S*XB~8wXp!a!4KQJ?Gz2ALHg{E&IHz0G19CZ3|);|%I{^bB)quwax z^=e!?6y{dJhEMZ`;T`Q;cbnh17Wn+K7?ggt0z+~iD0md1KfBd#bouw#ELP(1g0nx* zRZGBl0a-OtRk7?L7f1#S#Olp&dQ*Bmxe~Q*lXs*{Q$A9hktSPguhAQ zQ=rB!RJ71-UVfAYGg%PVWpuNW?v#j(}z@_f~0MJRF-2$;Wl-p zx9}cd8i`Qf$Fc`abeMd5?k%qq-uyL(V zNMSk`R#i_c&5S`qF2|BF{b6^RdFst?@8MN+K@s^20}s>5u8ykw+xZ@*5f;_xayEP! z!Mgdw1-4Wb<|}M`yHAhnBwtF6OF}n(dbW-kP>+93*=zxbie5KNm89yu!nL-=LYoV$ zB9Jm4MLr;_t`ABedNiRwcsmC%O(sZXnSa^*a`XY%zJ1B|i;_=0`b6r~fQj}dlG>p3 z(Uy8~TpoAcq1?6RM=ILV62v(;;TN}J02nDg&8QCOn1AP}cWzQn1Huhg*k(xj+3;pT z5D)jx>V$_W-8qBP_u)G)m0L2lt5FP7b|K^uX=7!lj%x zZQbE{&QFwvr!A5lt!H{c;TLMz_@k>J7q2RDCBdQ&|U7Y!Ytv4UO_(I18)eh|eZiY6i z$X;hAj})5~OMi~tH)$-)a{M>Qdg3S&+Jr90J_w5_n*;}$eWc>8&u&!VIuTbSFK6@S zXh*qA+Oa?z)R6ZR{D;OQ22|0BI>;Et4fLuicD@+LCt7e>MQX04)12|Z(UT!!E1YPR zOfxYQCgD%ll_P{DX@4pHHVKd z!+dwrjb$W1?dDfjf@qfT0&tHQNH#4(R{&G?Mv&79+Ob!h+=^m2i1J8JvpPq}iX z-%{X^YH+OPf1m{Ja$RFmV$v};|0)!6t%KU~4k3Q+hF*j6xRlRczM6zS=b=&L|0O>N z;f*&wt(DB|Q5VZ{sbtpO!6~fY&ZY>f%lL|y8XLDq$MvT^D;=c?&J>OYVuN^yj{|!t zAM-di)w((!OP4ISs~=x`xmMvImF5?fj2?y}JNC*Nn7${G+vPU}g;EN4cIqnhrT&w> zwlBZazIKa6!3{N93x5W#;D=NmJG*H+OWt+;H!SFD%Ph&%H~2+)qaQEg4nLCx?e9ev z4YpK}BHT%$ty>Dzja&BH>YeoZamspp{xqoWxqq?#uu;u zLdGb~gQ7d0X-+dnY^Py+#L_AcN$A_H5tYCDTQi-op+)*CrQh4I-+D2kZj)ZR=7iQK zhf92$yR!LIPiN+YY#1BcJ#0d+<4|~Al0;QRPWb8<@(IX79v(zr8ruDP8v6z~X+6u% zxnlDdon_i4*cP9RAf&6NGb5LiG&B26TCcCPD@pOCE^vKqQaG({ogy-6Jvh=SEGQH z8z1HdlBF4F%Y86(_l!ow2ugS0MMN*%8PV+d>qL+BcY!dn_&fl=hCsQ4z6dtgoutj; z>pP)pRQ^Rg>0BF0_&YZ)z{}Bj4rs(*DR>%Sh4?a(00??kvT#-FAKs4kCkwkbREZWE z78xuud-sQ6=FV2@P-Wb#)q^B-m~-1Bgjn8w9XmuM5zn-K@m4t?lk#*E-h2fdgC$v@ zK9o-+3k|#1PuZN3oM5+=%fpo--e`WMz_Ya?Z?{(rCYR+99x^`2dq6LC`#O`qm*+|z zKGRHlavR|Y0n2*4vvT>vQu!J^ zSp(zisW`HGlY<=6?0>Fm?+lKXq3AXIUJ+$qK#^%rKL5SFuU8&xR#B&)_e+xeF4YuC zu8vKN*&gwd)W6Y2iR#dJkbIQHQgm1`wbi!H5IdIhgSkU87VLRD-51gOuS&}R!oN$7 z&|hT2!nAPO8e_ejkzJ>dAVbiR%{?}C;@3o<*>x$sN`Y|>4s--EEDtJTB z86x=+Y>d9if;|DxVPNOor2+6HF4Z{w{bFG%3x`=Jy)~m4Ng6Py$T^e!Q>{3HwZ>Rq z$^T6I!Ss={YGK~Gu;6nkgMB1)He<~Pm}qM7E3wW{_SLwJAh}fPH`sEf4C=yU=Z)X_5RQyaDR)%%+>Tv^eTBa`A=R4|le_Zo3lABmVz&>$vcG%zU76G0-48 zad#`ikc2y%DJZI8{w52=^7>xiY&C(wi5orOcE-y)*D33Tn=$!V&EH(U8^g#|_c->$ z-yP{w=iRNmb};bb(-}`9(twG^pYn&_ZfMXvC9UnLZ@yyh5^B+UE-c&X#Wpoxtj?X# zcaPZFGvMng+8?)6(`h5O2?ga@zGOG;gLM$9`wxPQ#HE|REI-Nk9v zy8P*(70jfmr$GOW_VWDJHWTyp{@r{*xAmOaP(MAv^V$a9`nBy9Wh<6_O$K&9=Eb8hOg}g?{67`s!Lk`Xcc%G zv>NSAfC%rl-0TS-yc=Os=ir%-yaRQhsxVyI8MbqmdZ95W8a6m~oHIz39PygbA!;tUVZRw8y`eT`BSz10DF!pqW-K zCc99QGM60`+G82G6r4Hc?i|i3wg(+t@P0x=BoeqlSMDScAwM`jxh={B`F4CUHnG}q zNo;yrf_5`OZrJUxZZc>VKS#*z?h@fh20~W0`sjhF?Y+!!Trw3uq&x=2h;O3 z>^^OEOU1A@WcW{VU0b;U5|-b0Wp+iI)!Q|n62#wpWVqTZ%oRehhW0Y+Zsx(V>i&OL zPZA3kU%p>$VW;VUWL)8<$ge#-;a-p1A8@zT4tUzr1g?@nemY>GF6((y{FcpPSS9`w zhp%D?SWa(WS!}0c;ZE0Z6$tl(FqZW$zsBjc8m6g;4MQWqR1IZ@DOsNy-Ok1oZZE{< zX(OO#`i<~0$6#`>EsTAE4f6QBIZHQdsQVr<`x2t{*6Y)xn`K%+N%#p?F4;HY#; zAj2T-$vYsZ!ZYUCDBt&7)dREA)Y3;A@dOa77^Sc#I^4G0u9}tcNsMoe%(5iPzEx>@ zFlfCB?b5B*L~RIu^fHQ{>?MD){^enp7H;%9(tFJ zCZTEqY&BK?n;?ec|5p&h!^6q*zX)RZ{;wd$zrB-hJVC^I728`#2a`tp^YrH*(%+>y zVxzfJ{%`|Ajit5DVu{F!aS5f7kt*3HNOrRRd?w|16@pssMOL<}S48Qmm%doofFzbh)*UWvq0jswZR zA;~n-qB4nF9OvBxfMB5$ot zn6{jF<|RpZzjfSrp!7L`;W6ojo>K+!Omc@dDxg394DCAP%EX{vussl)VcfTv_6Sbf zH2ROqdH7lCvKQgf<~8>H;_D3XlT=-78(FW)me-{S=nY6s9#MTD@OETd*#S@o-4{T6;4VlzSjHME8OyS9xR41)@W7XM(G_VHq*54y){SwClKV^F>1F zeIkswbfq20bteVn_5IY35Of%b6vvpQAx~F25nTrnZveG{5UM1b#L1q4u&yj_6N9@l z?Xj-M`N1n0t!FB;j(ck+#C$_G1!2(6>&~6x$fEp+sHlw>UYFcxO7WjQ@DplRe3@6Q zd2l^EaL7Bp=-r2y+uj9XRE%;>9~z-PtI<8$Q^_^7G%>22*>B7e|4OHgzq>2R+j3+$ zw+}WDCd(PiW8ehxdX@eUZFd0`$CmC390&vm0Rjo`?(Wc7(8k>*5ZpDm1VV6k5AN;` zAwY0<4>UCH*4XQF&YYPub7$_o@2&OL+U)h!zpCk~1*>XT%l-w|6HBKfb6O9}qHxc%RfQ@A72#3eosHU05H9ylne|k1}rhB@9j9+ITbp7;edB%T+eNKMhx$oNQn)OS6c6(}jxVa-a7vA*a z_D4Z_6@nCkE{*aNnHH@Yffugwbqt){>j^kJWL%61{0S^pvJX1lkFe;70OD%O59-|z z|6Mrlm+g3`zTHKzhKLWir?TBAuzoKeupERYSXe1p`B~{$Iar0O87GL{EkF2dG<+Tt z;W)kSPU>##&gvfg%mGL8+MCnCXrs1!_VeRsmY1E_x1TnoJ{!W@p+C@_&UXvLMI&Y* zyC5RG3_|QfD0pd#h=rj3au!}6gYxC-n|!G9GxLsgCK}e&u*bV zQ72jj-+^&yFhL_~i17I4(s|=pCtN~B7(PCzr;E#w2$ZQ+JMfE1z|d^AcHzPI72SWh$p3z`8&JGZ;o>2OaK zVi&=K<7slwI^qf16Vt83>EK3}nD=`|vRE=?vOTgEGAc4}Y1^ObWSYURktfCMP%Y6~ zIJPTeLdkBvjJ)!oH1YizPo@|Iczf>svy4ply%5qJ<92!s5t-L}v@e9Hd_+!UGs2vl zoYb6rGx$1hbcl7ZJhd&vz^*w?;OdFZoV@qTVqRiJU)Bit1zhaFxf7rq>-UK74PUJi zLKMJr6Sg_)LC3FFaXe`+#lefL%#5^9K1hg>3CaiYj$rQ~wXw^+YGac_Z(}+ft3Ix# zgNi|d?;2Tc)E6MtyWbnX_~2f9EHoJj^j?1@dM$v>jeD)=F5<4`ZsRWFuHkOvF5&Ka z3)+m_oDXK$t*&5WADVUHGBzbpHD~+B5A#`03H6aL_aU zlhp0mDF?%)&{4KHbBG@Pol8E$dC*V!SbGUy+&ho$rdR=r8%g2_05%`) zouZnEnwFZ4nv9x;nvt4>n(GWmIZ}CEicXnFVikjnzm&pCZ)T?WK9@MmlhMj?CakzY znIP97atZTFbjDnHUHm9y>8&g2zQxR5G0NoAWX>epld{~;zJ2hyKKQ- zPuWN*PWh1%krI$Hl(LipNjdmfpR#N$+2_(P7m7OYM!Tl3=KY~*jqzcO7RPne!ra2~0v!}6AqmyTZ6p8WbBI!t z{&7A0k@1t);qk)y$LPMS$cspn$nbF4=;7$H5a%DWefl^>{j2y;dkKSw%+7P=u-U^= zvA-f}`ArksaYb{5qha4s$UWC_baTAp?$(Q66u;hXRh&tjc|R1KMV|5W6Pz{mMTeb4 zWaA1`JoVg4ZQ=B@gc}mAlRO(gSfAMs_`Q3Uc(}e@J?k1E2^UW9rh=yur~E;aPqj^% zK&?ilmoyRMpdXOI%4p>Nz4*)Zm$ff+$T!p@3MuK;v_>A^)4qKEl8nhs(;i>VWu*Jv z4Y>{Tnu<_{H`akWR`#__gmi?Woa_jYQK6oSAG1m>0n=V?2Gbr$7`u=L^?Jx0b$&gD zqSFXvHB&mO|APF$!Q`RpOuRMvwHvxleJr<BD&G;P8hs1}6uR2TKO$w%fOVZHJk7IoY0L4WbUtQ?93!Q>G6# zQS(qm%MhopBm$T{oX!OYIpWP}#(};756APc?S?^uI70nShz|nbMhI6#|ti z*+kXg0yIUU#HFmIbbhLN>ibo>?5glSP6~F zc%h@Es3nHwnWd#ApJktABd63-qNU1Gq@~UhlO@HJ&UEV(b-ui8oAA+Q{lIimeua!~ z_O;$pe?8Cin&Lg@(Lp`Qv@h^p@MyfgYig|Mz92YXs)(k*yl}TDxnOykMZQY0i+eTI zu5dkTEp9DoEnbMvM-mda7hT9AXPDH<-y!_icR4?`uJBCz7=C%QCtUEH_9O*4yX4qA zj_8g!jcAUTi8zeNjTnkZi(p{?5kbH{6Oqo5#@=t@ViqypEb!4x(y+fhf`(ngtbEv= zdn+-5hkb4MmU62sf`r|7Y$4l`a!akhMQ(j$W2AWG$4JCT`^c0W*+tw)>xeabuo-@8 zlWEilVftbwADy%3&WluMb{rGtQE&d~#Jl%9g(FSu!XpoWi{+8bR4)#6GvZ;wk%s~N z52$thI;!Q`bMLK#8kRg;8YVqE)N9sEI(qq+mW+tZGp#ztAu(5M2gV1l4s;G)9t_XT zSDfewH~LyWuC*>h(yywo@~=)9vl(SIOf=qWctX)2Aa=HTx~ux!thQL~Ww~x$THWzT zD}%N1oS=4HE%9Jl_La$;s`j{vVD^>OTv9oDt!|TJfL%PKqv+=R4^bT4tkL$F<&xgsiJmy{T z9b8_z*KUh#wKt|DLqf4W+`+@hL!m!I$AQCxgLGpxAYP}+kyt0Ykx3`JLA==MwCO|+ zGIO1=M?UmjKvo^4x%wFN+a6BbJMF0#zGFpvhPw|b7qVj~e11C*iOxdvEIgDv{5*6# z96Z8JjPqGumUceJ4bVw+IBu?2l2#g_UeI6*hZD(&52u^aaqY@%%VP`6PG{2nr(>xW z!)?3qN4lH&6=A37-K;^^U4)&W-9Avkj_EEINPTB^TR)a&XEmm1XEkF!frq+^!`^#s z)q~>#a=rr+jBR4K*I%pisM_v`y)js$@h}8E#@slsJ+)JK6rGQO?spJ(r9d=0=G(iV zoU2(So72sH?F2-*li2v`WSP}qkPThH*@yA?GDsUC1ZRDdIbD#|f~ zd+|n1Kpz6bt2t~NTKATXs{l6?A?DlKjr)LAgf1*XW?t=6w;aWs0@hmA9M%rjrt16{ zmU5={($oF#WI>*r6;STS4SP+Ux8^kKyLM3YyD=8;+S8Kn=C86@yc-;3HxYxfv3ymV z^Bfd6KYz~)Dnem-cZU;%-S>_PM?3sg*id+B7&C(vZEK}8Grk6AyM>yvm$Ln2LatZ1 z8O|t^j#_;?l=%^vl$A&iU!z;nsjmRHz$U?E~jy&J$O!rFa@gR>k) z)TfCp+sA`#-PiOkn%0i#m_ADhP;vY8D>$5l#XzOK)ZORIxsM=xozb`JcKTOUxF6$F z!R^g2;qYgAA;Vvqm@1h1acXheafT`y#w;!M`JLNKnC79{PF_G+pf2>3xgCc`g`Nb^ zsjW8A9^8*hmNj7UXxiS2W0CD-S=2w*9o&qIr}9gNBUg$ZzEAbjw$PT-c1mq1|5n~!UV2zt`?dC9XuH!7IO09(H z@bFv$YC?xvV+&OGsW4q0>SS0}Z>&00S`4kN1L=7vd5C*>d+2y5csRCHtSI}Mwy61j zY|-$Qy$d;?JFh%P22Bs0u=q7UoSjpF%7*5Xg*7{C9!AgIpt6rW!*iv#=3VEx7>I`c zJ%cfQ978!40u~5M9V=O#Q%z5kOmjtVQjM)Jx6atRZx!oCW27=gx2E`4Ntii(R+W2$ zv1}hAR<^pgYE7Q8V&CVmJgg!HW;KZBSB-u(YE2ym6#8L?GJ2LWo8tCLl}bVlzIG=y zQ!i6{Py!V6G1nZc&{Jz^cajH*fMgTX8P-cybXqFT+lKTL@9ELivx))MTQ;JNNV>I5 zy-DT_4akkdHmCv2oXKtx*4Ea?hv1`Qn=(zo?_5jGQFB8>L;T|&fxj>+H3awtBwd;~ zBW;gxSEpxZR=(rUam~5LqkwEP--25zYB3X0v7%*)4+vKmC)pd3)x}gVn%AHo>C656 z;x7}zV=4p7Yhg!UauQ6~z|jko(yPrDTZy~mAYd`WjlTpCoZ58P!9ojScfhIp###5) z=Ybc|h{T40ueP?>g#MZ;!eqga!ivE8!^0rMV8T$sNW;YZH880n{JthR&~@?y?eP=1 zNvw+qax`Hd>??4&oU{H%NBCJ>Q7*~fW*#P03&+uP&m^IIC?%$7S+8HcAN{Q0~U;$viTe3Qu}Au%}M~^XVXT-wS56u^!Me4tHN-P z?6!tCpg6_E9&>qPPYJPrJR;gMea+Pv|&^&$4nu6n1msH~n- zDybeg^!e{|)#EEe-@QW|AMd@mIDG&Bgwg+2wxhapZ!G@1HGma<^ro@iiVKH>e^)|D zos+TNwhM=C03jc`)L3uqU&~Llbz-SRLx(BI%}&IX8Nm#@n?oM|RIVM1iu@6FzH(RZ z4*a;gIqBiZa<~KzBW(Cuedf~7G$lyaaAM5?IWEtyq zy>M6s=<%S>kN%~c7jZ>Z`=k3d4^^N$P`O|O6#GE~W)b11T=xH0GZvhqo|2F*n89e^+WdHYNvOgl)Mh`52*B=q_ zbOVN%usiUDy8{dhFt07WzlpOcTI9pJP;N^@n}^(g#dfIdXp>JZmTnHO8Oe&$sZ~$Z+TIqQ!fAHr7OZl|>bGA6<5Dla3n; zfd(!ykubFwBHVC4C1DnkNC{xI13w`07fZohA$=o;ouTmegjb4&*~btOg!>;t(xNxr zB5=6UFfWilkix#E^#2Uc8UynZ^DiOaSARk=ktj0%B>0Iq7#&OzSvU(I3={GKO@FriipF7NW<(RZ4km{Q20B;J4C@4V01IUsUW~!lKUILPlUsGVu-K=^j`3O zh-E|ii3?vHp%iWuU<3b;Ln%gp9?a%LL~it$My-umUSh0B9HAv z`XOm@&I0;F_gjaF931Vf85g=dd`rRVNh&A5%mO3iQCBB7Y-;Z3*{Zk$|B? zCZ&SSr}R&NkBNg(!4#2!1GK;>GIz(LoNoX7GGJSI)NIs1dy%uWVO9f}D;uq3dhx1V zv)O(47^}4XeS>E4*(e0%r- zRzRye3h)Dsy*lvqA?XW&_70-8H8gwsstXGYk$zqtok8?p}Xi72MR+`)^{Y z9V2K99&YLdEpN^pIUIa4dGnvzwdA;$^MYXVZ!*tf&8*3QMm*8t*Z=oMXo@Jc*rWW( zA%W;GCBOs`UEN5t+p z{QBxSmmH!~-<80txks4}iQHniZu|GY7TDh9y1!=1u!Ab0=(ySR%VQTs_)I>xXDOcm`48>p)uC!hmYhoa$h1tXS)MSLRq;m z3aP)(h^M3>slGL`BA1gde@V=!@TD)bnim6`=KHT7R#5o}{hH?cllVfm)(b#Nj@BO< z5)?>cRj&DqlC%qx^}-!(gU|oJDKt^qbv9<8xO=F2>EevLjKYrt;g9NW02AbxVUaa5C z$t{P!Jjq`l_y0fsQ)Bwr;x7;94E(^1JVN!kg_1QHekZP54>Ls;8YU7mxfbs$bA7WC zr^+?%NcuDXb7O}@_{z9$bJNeN&ybK9J_4zo{LjUIyG=KP%HRL_ zK0E&lXGn;gLGix`|IQiyAv20_WB%1R{CoJnI_Q5r6eY?xVes!`MQAaRB;azSN#7xV zA^-f}hGdwu;&4II8)(QYWS<2n(cPq#B9Gny1FVos7m42*4uXT!xYYpku!%(KSfy5K zT*ZXNR?4$ErGK2!5T%V1|F~^4e-VI+#7(;JZG<`!cYbbeN>`}=-p{3W7|{ANFC6gh z)ICmW-Tg8W+7)k2@(}y{-o2fmgU!VBCxsD(3Gior_1kT|NCVV8RYOr?5@{gnZG6## z1~2gDP{}sfN0#7ii(iSA{QFbpcM zD_JkrDqUFbtaTOfd;5)HS7O7;i(9A6e_TwIYls(Y4so)q2!v!wce#ouLV`j7og_4g zk&juZct;;+bc?~7*iif8b|`H?a}My= zRr2&3J@}_VT+uAh4UI;(P@o%XUEF?88^D>%haeYsrS!);TIO7OSxbdW1Lx*TYF zVzqy4YimWY$Zw_gQC645i|0o`YpZ}%l=ZQxdE-!)d81BnMM4sQ0YPIFlpjtPMY^*mhBmPZz3sOgg2krvi9*Dg`}nG-Xs#zYct*ed6u zCg%*!>m|D-xwx7xwU%|#b@@GiZgphN0W-JCD+K4F#*oV~Jo3v5+T7wAoD;6nlICKW zY$jogXmTFVw=_ENr8)U_2Q=v&#RiPvB0NKF{zATm+NR&04% z@YOaHl~q_`Vl4{{T3cM{+1MTAKa%+zAKC4L@n)x1{*lWT^B%@v5 zyII?_?1`x2ObT|E96K00WJ7;^d$!^F4=Wfp<;-*(l$syj@_&XK>*WF*)KRfn-(8mc&%iymUwGjI4A=DxvPr zGk%X9CY3H=)YbO4N55>slbBB=F`jsQ*fCqGPBv7w!ZcSjhbOp>hbI=^qES_YHIent zQ8Vi?oGGy@7w4!T~+r z`Xc0kDt3=>l;(U~kM@Q;)(zwC4bHfav?1K?fRA|PQJx=4C`z8+SuaojKybQbrQlCT zUq?Mkp1_UiE`ci;zGJchMkm2}Km2*%_97w9CFh=0=I#l9B*m^Za8)J>c^g-8Y)`9| zH~ZTayfr2t2`LjzJOqn5gg~~k3pkcOco)1~AtXAp(9F=>aA_|**;T!%hz%sQv>=nE z{DMN$8@ip_Y{5)T%0MbWN<+#+%0epqjkKFsiDcr94XOd|wfsy#@n{VNCJps!8u3Sc zBYjJKQ=cJ7y=#MOq-(_$%0Xks8Q)tc>K(bE)C>-)-Om|_&StxeLyKw7&HfChbf-+7 z`GB1E;`ZkD{Pz0x^7i)j-1gcPjj?1D=$C!yeQng^drzifhTRNmeuX7!mbV&jVO1H_ z?1kM_Evek3Yk9~&aUsmNyMBa3`k|u|rg5nem-5=Xp}DPX+Biiya0^KB>t^I-Bz=y=UPz&9X3!%M?Y!$%`f#9PFF@=3vYZ7btAW3zqU zBip&~!grT(_r(}uW?d#a-+czU0Ey$6qtJfFf%gdC_+7Jer}Jm$9Oqc)nhWGz%-#60 zf-%!E&=}TO;+XnaQHG*`rocS!JpVl3yg;^NYsTXk?C#6my0P7iaREbzPO$gjUF`+d zuHufGxnm!?MSi$C^jaUGy}Qb8Yk? z!~NislRqIX;vhDk7Fw(rh?P$-Dux0?%cm0+`w_&;XP^-C7DUOXtq`jU;^fmGi{UUW z%b+qJ=5wmdpxGTpaLUo6#2Kb?D$%1(9>#Jiu!;B3jyZBl)MJ|eiPoagDc-5pDc7mj z`My)7Q>HTh0Q9m&8QT=tsnaRhsnMy>Y0xR!sZ30co|sw7$WTjfUCT^RONSnBA7`Ir zA8VgzA8(%=JnZ&U{v4@Ao0zWYXWsVYIc|%3rz$Z+)8LU)@Cu#VpxfZ8Q}hZ$bo{{Z z+wIVEN{?EAL>B!zlVbcyY|${swioDrJN5kWobe9!PSm6EA!da}m{FK~JeDMJcPM)B zVtW8|cMj)~(=KhmC``r@o1Kt6G`tNuf8|loF5@fXt7E`a6+1t4uzhvTQ7e0#jJS<@ zUU%+%esPX+9)2!+K77t_E_tW!5&w|ZuI;PuE9R@ZM&3o$#neU7#n465#o|ZmN9#vv zpD3Ip94nkC950;Q71K0mIAl0zIK2LIeP|hUvV8&~*(L!Ioh#hYcqF&$K50KmtWlgK z`X$~Bb`9Qx)V!XA4$e-y*5~BwPKyS~1cL@*4-a5ny<3G(oT_ERkkGp_} z=tB+OKB+VHhj)HdBFJh1@4_+5ztHB$q+nKx)5gjqU{?H~t&z#VtfHh1m5GZh&!;Vs zNsFsAp-l}_A5^JLB&5ZGnWCwJl>!$A zL76Ic1-vRbC2IQkgu$VArln3z?D8#Asg)y2$LhzbX7o143sVlvt1P#=L^ z%0n%+3{W_tO02oVfRYe2L~dGh{-svjLq)rkQ8kHyAt7;y9z+MSG;OGr)GjMmonsiM zWiBwpQ{tu_ryr*qXJDaap=Y6Efli1)kf@m`KV&^*266?Vg5*uZ&y&s@&!eF4=4G9C zo_{{iIghPXztg%Czf-%DyVJXSzgXy9;$7ff;hpDQW~14u+NtTQ{ztJbs}vr-K%*-;JW89gq=QB9PY_YKla8nQDg4RTDH3^Ovbh3BQ;mS*W2 zbSjjItSUT1Jxe@OJzG43JPSM%b&BT7P_6RlOXEBnJR?0TJTpBzJOe%R_{E7z`PH@6 z)zoLz^tseji3->9*UHy&*Gkt4*DBF8Pn6PUFs$nMRcw`|O7dpetjau#_%&=*muJx$ zRF70nRN7{V8#IZEqBLoW-_8Q}O?%Q0E zH7NRM`G{xc36+kilc?^NM3-I6BJ96+jcwKPd9R-6%)*u&+g9b&f?7A%qGty&uY#@La99JD=ybMNGs$kq_9=ON7hHz zN6JUjN72XdQRGqSQF^u1x7;_^x74=~s*UB?sdlM#sdQ=lM&&h?t(UBq3I9gr&1CK? z?lZeKLFypktx~IHPo>AIeyTTRP%3XG5K85dT~&LEKdK6r601g+(agl}(_OJ#)$mF>=4>?1(+yb8y(=$*1V%O@Rw>|z8|A9@1*X<~I+aO9AZrAj9F2S|Ybu=*jlx80ES&&OS;#LTRcI5GG+5--PcGqBsJE#SK#jd4o#43= zS15hAsuMj|7CGH-{kA@IiPE-~TOz%5wL*USc(Tx%qu#6GzCIOd;4vP-LJhpe>zKJB z!E(Xe(MjUj9jj=|i~50vyCpc=oJMKga={#?$*h?qtKoXk(kt77Mj0;|FCE>Aipe>v zgZir_jx^bW`Iq&mOLa@mOBYKhOW{khOT$YHOOi+Gw(-|#joM!NUSeLV%efr|9TgpU z9c3Lw9aTQxe2RVYZD)n%geHY%g{Fn(J0}_~4Xq3<4XxKL)~%KsPU=q@Na{%%h?W$N zXl#=kb?>$BC6@D!W_@R`ExRo58`c|MEQubWAH{sq63BflA)1Y{9B6pE1UyQ(PX44r zFf(Rh-q6+HyyS5da2>rf$G0kVGyCY`Cn$nG6X+67TpkS0@k}AElmf^8cZgoA`uJ4c z6``Q!`1HkpMf95X+L^(hI%KNmtX+Z)%Kl*Qeq-(oOAHI<_pUqx*NVei^9?Hu^9;)j ziwvvQzpWRePX_NR=+9y4&vNO{qpr>b@A2&M95jKO_M7&a4tlQyE~$OKtd&R4=w2#A zEPNu?O4m!GXO}NOb%>qJv|YAc+I2{s%ns~rT_Honed2_)vvU=p3SJRZ!JEFqgLFWA zAaaksK1omhPv3-e{iIK(N#;lkC5xN`UjyW`B~ZG9bTVgsIpZ89!N4s*>d6a+MCyH%BE@rTwi;O zxtQ6QxtKYac`8{eIV;)sBRunZEI7r**ekg!*($jzIVySVSnW8!;)XJIvy?z0Of?PfOI20Ux5Yn+X^_IUOLC%7m0 zCwM0WB)BB_BzU@!(UFP~ijm_H8w*ATdn*H;?19_je1h%}k5TQU`aLx4X;DYHP zw=cIZ+cmCNq+z5_zkR;oVe}fH6i4V!u7+Kiu~B`xb?+xir4hPG=uwPBuBsY zmi<WuUTJ=l1>}HOeZrd#xwhxj$xLMXDXS_W>$`8-k*+a zmYZrqola*~nrc>y*UiWoK4M(=gOO`^#HsFkIj1eP{j0*& za`v)O{Ar`PwB(fJwB*#}bj=jaG|g03vyR0N+-bRVsha8YDf4Obsq^VPDLiRnBRPfB z3G#hv@}o2Iy_};)JMufDJ4`zjJGMJVI}R6Ub%TUP-02jf*v<)jON1XA)7;WNj&j$n z97RhS zs&NU)jrA6a;$75A0cW2FI364@`-)!3FlZ;hg*<5L`*%w@&y1DHhC4fEEgo$5VbUe; z`h}~Mbd+gSjs8(b=gs8?As(C(7HZQB>+T~Vv1JMS`IY0X)*5&a{Q0fR*wNaF)0H;$ zWy`9R%j%JkEWzX6zFV8(6ykH@%e~cJ@iTq9^Am}tdzMEWo?YD)MXD(Yzeh`Q%WP#} z(Y&vNGpyRPVLmBE-jQAqPQeS8i2Bt}?Cdv&$8Jo4qq}*(R*!}C(pQdG>nGQabefhs zdVPkDgk;i>x5)uh(aWe)WJ^1U^HZI=((8Vd$vF-zEh7@uyTB$gqI{x=Pc4NLdtmc| z;prN8{cO+rA$QSP0cQ2zKp9O>5JUtc)iNI`aAh@PVAPJ1>^a+0@)S4 zgnQO$1@nydYF?c$ZH-F6qA9>R%y->A4{JBlERa_e}xMwBs z0WU(>9Ho22*`uDc@bZDej(Hwb`|yr8{ThVIpSYb$QD25*!4uW;d?`J^Hyrq`9D1#Y zheYB~)gp~gYV!fZyDSglT`-;)GO6N!2`TI(Mp%CcGiANdo8{~3^mk@KB@Qjh>4>B-4w+Y!1Rycs8HPtgkS^6apLfG}^n=Z8{Lqm;)7+Ui^C0iz zK~ebD2xToLcq3}c6=U1ek)G*(5BdUuKoQu5(}a#a9;%BfdnYk+@wbY$=I7x?-2)Q8 zt|)3ooRMnlKq^dfwDhfksRoDVx1}cY7sMREP7Br%-d`!fQ;}TQRn8gLI~((7fmM2* z$B81p=-kjDedv%(if05#@z>O-#L+Zcw~<0)ldvZRNJ5oQ0v)FQl})23DeIei;FIYV zthX9+T0C1Vox6}ZCN0sYO|)dr%=E6Th>>4UHiAAQAHqJxQ|({8PDLoYhYup<-K*d5 zmd<N$Y}}Ll?R!sdBpV^|krdl+wp8hBruAw-JjF*PcrS4hNo^;8nO3Qx{Hi#*5!b65 z?Gz%_qH};9+ZM$rs*G}3N8A&Yx-2ku&Gh6v#EUwfx`sKzaH7s%!HKz5x)@XTOC{i5 zV(?oph0e9IG|4KMvf%JAUzKe_LdNg8jWL4DwIY0^$ogA+!eiey>{xah2!@!-hp}+~ z9r=}RF=qtCGuK@>^RR2B45;an*sjhTCh9 zWx-L=%3!`BIM8ppO#sOaGb1zMWTmSbIbRmUvk#%8d60qxRt_O~Cd0!ITkus!d{=E1 z+kJ9$4y}B`E5EE(cVZ(@6ZRQ=d`>K;ArBWVil6Kn(`|M2u_a-9?%_b5HQ&iHvtC&- zna?2hH&9)7i01f;LeeS1jqteg>~<*Q5_1ak-0OZlmvT8{1BxK*8W%$3di`?i3MrY^ zfl;}%TNLBZ@X$X&snk&JBTD|!`K6JM+NO$1p)!daU7#$8{8- zIlDM%QwlIT)^fIik28X&So>MwE}0QOQ%4}u8@zlQ-gn7(Y^MCWk5?20TZFJcgxHde z%5Cac`mCEVxBs!9asRF&ggI0v(8IHpm6)7**|Ct8SRpH=hAo&KVXu`ZlmD|*N(Ns*NAbNA6(UTUZm)nz1ZXMUC2mAsl{HA15EGgf9ncr;mV_`HGNkM4#KiQRqj*Ix*>X~STah;B(B=`aC~*Uvu(iq5=317^ytUqW zgnHn(X@>|ZBe-z}BIIT1lwlZ@2xM8qSMW^PMkW0E$3L{SQxLy7a>wVc?1r#SwAJ*z zBRA+;gx+_-I`L<=+0%K9Q-aAOucwRqPEEXNisN4utlh!;pyyQfWu587FjeHESfL~~ zDh+ABxRj2=Vd=XqS2^zW&9i>9ycbQ~v($ijEC zSJ~ZjGR|pxfD*#%ysN!_>&$Z9kkPgky9mqanT)~hSTjR44M>!ovcG;!7rGWCKF>{{ zhqj6Y z5V=lk$ku(RDc5>@0T7X^V|DBNx_07+x{M~btnLDSkq6=O&1ogxjVOK_vGI04Ho11X z?U#aU2aNm`U{QF*>ItoO+YOi}_FR)6zm;WUZMT!P%UY-=)|mfUeE7HdcEqIfZjI*! zT`=&<)hw>(Pqe?z5o6Y#Xlvi?#k*M4O28pv^YX7=~M?VYJ!$g`9Thl@eCx z0AwIByrUgXfy~uR9KPI7(EGU&!eA_Ub1o5TSM#ndX>By=U^Pp^s~%TCV~Df!wNa z$5FNwdSue-cmBql-RI!+6-2x$-}d~+VNc~}jj&c1P6h!agm>sMeWyi@p-Gpa!gOmr z;dl>17KM}SqhGa1>yjlLU84NRz5*!&WeDg#PBcgt^~zTrIak!bxzH9BoN!`KpK-y| zh9YC86p3?6p)Ty{OfQyJz0>&KhOdhBN+wOci~kni`Ph)f6(d3xMUH#@n=(cY_I^5c zVgl<;@FnA+ITyVI$`gZItKwU6t!Yrf#fi#~QhMk&Q%zTV*?bAQItwWcY)zAdw&=#qETR|qX&Z6pXCU!F?Xde zwv&Ipp3?ql&LKU!Q&XN^NSIhTJ5v|ahBb0F>Ch1|6&++n`*D-MLsxprZ>XG8t!Nws ze)=iV%<0J#E`(E6bpsDRTe{N(cu*-WJFKu8qbE0O#Fem^Qv#s%eY5pg7}#Mfy4a!Cr6h@yVgLliamI$ENRFF zUF(Cf^iR>&%h#B+3bLUhw29|L@v%g%Qfc0}eRB};0D&RkO*8dq#Vz@=-+Qv?sSg75OYW*X{l2Z_s1=N!V#*t8A%0(xG}^QsDQ-DH{fC zR6YCH<4Fx@`mpiUa8%|O$>p+5v9fM#+U>sNoViSPGZaYMwtvej5&KmCbKL zrkmn3y61EJp^RzY86z{VY)KKx9P*Wjv2E*^lzG%AtYfhZJdD4yxh3d=mEp1qY${fx zfArU9-Ht{)ah&!((@laz-`K#gvYQLM=<@X2zm2XB78*#2KUFqlAR=?sdcyG=tJ&Bk ztg6qJptCWQnNQZXFl9`SI1D>~)af6!wsdoCe4fA2TW823nR7bJLth0+48}2@Z_6sy zv+NsfPUSbmgNfz%Ju27F7hAFy=5{>NhEs^~SLGA)W2KYbznT|Qs)n|Y>m4>=&Zx9D z?Y=}-DFXJg!t4F8tTi;)8NE34L*&TIn|mwyf?tQ3ROF_4x8^9qBTF7t_#|4Df${K$ zaPh6Tggp;{O!J-V7V+TeLuVhvD}difaj-eO=6g2h`9*>h;B4cIkYck4IclvxxGlei zV(k}{bC^n21&<5apvP6dyg@_33SJj``;H|rGpGF1JIj4q`qeMY6m|JsR&N+nDM{!8 zH9ecqLloV=*OjDw$E6gn1%x z9}5E!P|_0MBI^B!?FC#wP&E==%=R4Cisn0d-xU>2O~-~)t$$*&tdNqT;5H$#; ze8AUDDP86$Pr~aq=?nw#CQ|F$pK*xiKjo@^T%%hc!s)#r0C*v4+svA(3>&Y}Jmx~h zF&VR77K5%ZTS^@bkL$OKoimktE{1!$N#@?e*Qwyy3dTv#z`m%Px6a?%-0W^jk08=b zUg4EBaqZvSz_Z!m_hr&`HR%j&X7(Sa+yuvO9ZGRE3P=W!$dD!N)$4eZWOB7Kefs&>Uygie zzI8^4oo9D1wm_#}K2s{4+l|nws9-E96qNSqVzr)7MywisylOgvIS(j+={`zh;9V`8 zjv3AK5Y`**imsz^Rq?@bp51<=um7bTJHVPYf>Mh03oAbj2F|1GJ0>`Nfu!lU5!2U4 zX(Uc=y&SuamFOK^of755?Y5^^w>{cEyYCTiMvhUMEfpV1I(wc_n#^zXg?RrDXXnr? z3eaWQcWv9YZQHhOyldOGZQHhO+qO~fi|UB3K@B=OB8T|{&dFSRua~V(@6;SDEoq19 zFuvI@`xAe+S+PId*=&Ynba7qj)%2XLTo(K}(uB6Jt=3erE$>+&iP)z_y2&MQT&0e$ z^-G43G@qqTp1LyzI=2rg)~yb3pE60Z<28|A{lo)!PJ!lN^~{_)V(UJCwhzf*e2jTx zKk~Avca8Lr>Z~KLCF*gE)qGQ1rC+RLlpON(pp4s4yK0aL$Aj63qx}d-P-n z&A{Cfp9VsB2OiGg;bQxq&?9`(ZrNU5ay9z8?6&7Te$o+;B!AA_{_0)pc-kwgWbi@E zwe#x=W`qWCLr;iG{#71{U)M0z5L1g6xWY17D@b#oAWssAM*tQa5W>|3l;Fn&6bJy{ zit*#BLfOussdOnJtx4hP0R8J_5-0Wti~yh`Kk+GN_xAH9xEiz7@;9yeyHKt|&UdTF z`}W##_8qtP_EqPmj_LObq4Sr6E`9SyqIml}@o?>%w6@#xLFnp{;6(yj`bkc^1n92= zCuyNv9i)=|3-r^WSs9}KPxaW*lxWZfgI4k*g*DERtY#lY>mMUzCDpNNY?|{>hEkHx z6k8$RRaR_+TEZET5;wR+2^dfN4t%|h?d=x4@Z*T@HfH|WHOmHG-aQ=n?lGFQ@Xx@U z*M1+*og8=1Dom2EDUqX9J0V|ttQGxkZP^c_UzI#gJfnGi3rgjMD?433-kv|9_U~M$ z(>ZKdp{^*e%~YPEbBk=iV{F?P^J1r@LciEktDEc;9HG%d<@>!d;?fKGZN!>Vl57k> z;rA5%tQlH;6olIX$UuD8xK&J>s{$G=DYV@iDusvm*A%peDd6bSn3u^OtYZb0;Iz$O+e% zjz)?ICBC)sr5z;fjrsQJ{wj2;=6ij0TU6fmRWU&2hH)!=v*3sGTZ!!?LZhG3!r!6+ zzG523ipSj#j5TMV&GXAv5|aiNEh5$h(Ro@-ozvQdFa_q2EqKUYQjvp#Kq?B}&S1eH zPDhsf`#nBL|Fja&G4mJuo&0Xhw#}6ccr#q;f*=l%cxoqSgOPm>#{_au8~I~_7-#8+ zv#T@t+<~VX%O9W$ri_?QKf3{_V=u!KDtdU?TGRE{nGE^WrhXC%ZApk}JI<7nbZ&aN z3zj}(J4bXPm1-(xxNBn=5es}r*7)2B9szg(JK^x^!W!~x2)yKr;dj~+F#lzD$R+Htaq44Xd2ueuuaT3bg%~f-QswoHG0oDFJ4Y{-H2>Ul zj=`RL3KIAhX5ZJsr5|eYP&bcyuAS!V1^PQr+TrwA$A-vj(nVNBIUw4C=zm8AGjiK3Nzj z*|1nKT0K+)lni(=p=sTtBulE?@{F^%FgM{&(_UTBNP#$xDbvG*=|v>!X0(k7D!+#` zupWlGu@i@212i!%<~joET)=t#96eAP6xLg;`|}HGP8bHf1{UV7I1smCMA|n z=GOW{^NAvc(`fo%d*nI6VGtL&1$5IGCiX!%jYU6xq?k`-FGhxr%IGl`B$U)cv`w{} z1Ut67;S`C8Q@5-xg}s32%LZd-&1%>62oB!vRT9o6UDNzMqL5=oiuz4nbL1URrrL*O z>95#}G$`+_b{8B6{^W>~RzSz(RE{UuHu#=5BX%=b$+C9+f&6;`GQT+RIt`MvM9@Xb z7H9t=>vQ2~uz}Yb=~Rz%#|B3z3Dgf!FOhF?}@tPWyC$0NG#kXtVH9DasY2k&5NWcs){f)N1uiBtSFM5z254aJlriCnvZb%fzGzobEsB^jrJ zBEE0V*tTCb%2I3xP!p$wpGspGFdldTgks3PnZ582by;py1aTyiR=E1icCopM-i3m% zGS0^gXEuqkPiu)lh7Hr|;O0*tX*W7#!ubMF(l3*JjYl7OtNlp0h{>CKY=~A8JL5`! zCK#M2Y>F9d5onxj+5!}6dZ#2t&%qCRg%42?MjWg}0nc_pJ0rYk zVnA|DF-z@;8SSS8BzHDNxZOz2b!KkrR!x*qJYFrngVucoPgkA6{?L6iG~#f-XQYy> zxOuxIh)jKIK4PenijAU{0FI#ADC`8Sv-d{j>f%qgzc}rnG2YrlC zsNq6}w5+GAjq%?{2C~o3=E-DjM+Id)pk;zTEOCov7*Grj&^V3?5l)iGU2+!P-KPhU z^zNFL&khA@1tDd7?PmQxVU>;Oe@mxDe*3ha=fhV{(!Dy{92Ub*hcC?>rhmpLJPsqD zMmGIP)CAX_-zb2@HO|q{os^6{fGcUf+a-eqH}L6y1^%d3h(}VWg|7yw%VNq@_4yNnS$~d;5**5DvNXsRwfSdrRN4DwHH@2nPcL&gbQ#BRqE1_1}-e zL!Wuek9wd#w2SwvSD4(DcFEt!mt6>Eh``|w6()>8-a~1)X8aaM(F)L{hj2L4;zf~+ zhD>itHb)57d9%uz5Vmm~qP&<7A0gk)$Km#(SzO%=%!$a)8=&5a3M2KFPZot!lYm>1 zvV<%4B*CEI->^te7$d9~j99WO$(bz>q#RFEzp%0w`3GfF?#DDS1`89aQr)D@i6l~| z6-;7EQm1|(b=&Rco)SYT4lBq`h@IeDMM$bhFpbtGi?b5WeQR}4g@VxM6R%_ zWcx8*7H^&C2*|0K`awIzU9_V=oY(Ay4X>?)+qAaD8l-F=q^RPp6+M=d30g0}k53X} z$P!wd&6nNY2K+=?QM1a^lBKD**Y9r9NjckflX^yJ{GcW|hu1>=h_*WMdM2eKQ;xnG ziz{+Nz7oTWnDJ@|O)3?B;a3`(PE1L&ZDK9%uoZAmC`Ac*)pslhSZCUvvnF>Wf~1`C z=F3~=d<1S1L&r5yDveR%3=KmpN^Cs<6%odR50tgSUby;ZpD0?meMqe{@Y^RIAC>ZQ zWn$xXU*63VA;8Nz)KB6Yh@^(V2Uj8{((v4!+qeK$y$Y{FVr~lEXnr>*d^3@cJmj zHW&{gwvy0^h&8i_i58QJWNx-bMc6;yBFH#N*Z)dVyV13ie5~&(i<;*O#8gRS-hTSi z`0!g>_O^*Bs#>?&*GvCCF^Jn;(wOPEz@bmo$`iZch~_Lq2SmewJ8lAP_3!DZP(Tiy znU^&~&KZ_*OgSt)-jEC63?#3ygW26|T{}(bf(jjzN4V-zpsl3L>0`gndF}B>KY{>B z<|bfIVG1V7diIwMjboFKxwbrzt{pl_Z`B2}8B9X9_m}N2Z#t=Ti02gz=|RW!P1TaZ z!3n>to$kzbrytL5sQwha1|@PvDY>O7u|#a6&3T;!s%;sRSkGI6@GQ6ODc{#n>QMRz z&Y#FF<#od#2(y(9Iu5*$$!nEf+!3?PoRhkOEFw#dxvCF1$#A&Cn#hW*GkV-pp;oIC zliaJ*?;vVh$@1QQ!rAY(@Aw|Aer5I=%{5b$DW9F>rbYT3X@BDo`(QMhw7KXgtS=r5H_qOckIyrZ&>i6d%T^WzUrV%P|sk9A4y$hV$BV@Ya)PSvUB^bh&R6 zMVY`K)Io({X+SZH=qj4WEZG!qHZ(L!5(Y)ACs`_N^$ct9TbV%bT&;FXVG}YYh2Sr< z-iWY|ln3J1CTlNjh#<&LSF|d2TL9k!^WG_9kUh~Xf`gR&=_!;5ABC&78#`wnVF6x2 z^cMDg7685UxAUQSE6yBa)rp%1FV;49XZ+I$#yy5~NEx$EQ8ypPToTXYN zm)k8M_UV?$vUzTb9F?&5Di$=IRD=sU=(AQE9QhN@Lcd7jO~Awx>jfI`rHZgxA+{nn zV1KWTW~qS{E);k^B;JR+iatV#ehcHLu6oS8o7!LZgNUwLfr_u{UKREJ?kEOpmFja3Uz=dirD8>3CA+=t3&Y-h<*g)T`PsV%l255nQv0cY#e| z?w-Og7v6=bE(i%Bheb(Vj&{3lYYk4Kmpk6s@GTGafJl~e_(BpMyA z_}Y^27MbRiswTv@kHCwD{u~+oehvv{r*tnRMj`2>VfrQ1hNO=gh@a7yVFB02OHf`I zAV{nkXWI{?a>bKV(oqivO;y~5h-H>8h`u}7(~I(*eBET;$NuH3U+XpsTeIHRRyvdp zWP}BzgWSLjC=r0cJDUgSjS``c4T8ymzl|W}9T_lx^P}?skB-s9gqXz#2E^=78$J7V z#}pY(BHrs4RC0RuPIx-W;pcCO;Fk#pR<7g!GY7e29}O3yH0%>CriuUCi>k$0kz1ZK zIZ^8F1W}~d){ULGX`)AI!QmK)Pk!GPori@4r`f#9S;D@Ie4lc6&O7-gor|`%S>I15 z+MgDsre;9B9K1kKobSY(ToJgP-UEF8gN9&R2&_6G_A~GJV=?uw@+o2aUsLB^kl(9F>kptw>d@J#dK-db7Q>4K_nNPZ+2TZ z2N|Enyx9|4CDAM&N2=THl}IDnv@yalv*!<;44NEda`B(HB(A?em8h&^jU4*zlV#Nt z%4RwX6&xFL9eHN++P+C=oZ%@aNiYdH$|H{u3WWFctdRe>BRYsNbhDZsxnK>oPF&(t zy6OiYk>J_>GYX8+*W}Q6EWw0rjkN%TDB${W7Dcpbgp|>C_V5tXjCj3QjPqi{ahlTZ zp}Lp)WL-mXhbx9SQ#)~=ty5S#^M{w^9hvLa-J9YY8C#BHl8)Bcnx~C~LanYK|1|rA z!d_62ZCtC-Zw2Idv;(!9#QgYDZ5;<+LTD~3p8Rtt&OR^x8Iac>$frcAGCugXlG-YA zt^C>a%Q(#{cCv!>o}k&TI&al0>Y0$Jwob)W?-phFE07tzE3b@3U8EjZ+F<+&B6~{< z^6hHsb=l=D_Hp>~Y9anC-O)cr-gAefg3GmNyEeb`OS6esvu@#99O#1yg|SBTj5Le? z=UmgRocu@~sLdZ`d~U7^KP28F>)ar+m}{Kv+;W{lboFw$P_p&3wqLsWBv=)hWCCI- zo~+rpztBx0rj{KdHFu{x%$!7!>disC`*9kudW`)bBH z70@V@arH7i{<@Mn;q-Cw|4mgYG12^gJ>PguSEJKozkq4hOh*5k4}|gm(+9#q&&K#a zbs*cG?rzE|Ew?qqD$arlgwQCa)Sw7b{J@zlHk-EbE@z_fWlD@?Hqwyf(@V*a1W^E9 zi)nkbtpFTV0Tc|W{Ku*IbL{L26lVDo$VE&#cv9 z{{9$z=t}9aDJQ9kR`VDFNB=@Le+C8WhoF1g&UJ+PEZ(+%%n;0 z`qJ>>z(pd&C@_1+P*DN#X*g`PI!33ww*Hw!qJbF%TWX&S&;Wa0?xAqLFhe0cXikaZ9~r>rrh{aMQ}{(=x27@MDo9 zBOnxOObj~(C@?4moi(Zl4MTrKDtbbEugo>Zkt2yL)uz=Me&|Zth%E6*&)&-h=@T>~ zM~IzA!^dif5G56P=D`qsnAbR5+#;a>GZ>;o2kA0xR1@$ws=~8opF)IBIQ?oYt?G)T zyH%w*-r`o1(8>dGNpS7x~?Oi_j1K@xGxkvxxH z5LPs292=J$xNOP_8nVtpS}HsAg1<&J5F1RRSooka;{3{SfsovO;g*u5+9C2Gw9eha z2mc1OZH2@d+oCLXCJ-i?2TAHmP}E-Ql58Sic4oa|$UM%RJPcK~ao>ZrdBGWweDO$n zN2)K7xI!&HQJrw~e~vD4jd&^+NV$0o=oILy$HXWh&y|cx5d&{n3_*N3 z^fj2O9R2+9e9;oB^^mG-ohs_Bxug6_7il0DmW!8@Btz2J5B_b7e^x z?$K!37TU@j@}eW4RLpcf3ia(h_22w8o`AcAyZhe#{Tt_q3L84;DOYB!N{&fOiH%kP z3DZrdj9o)1GPq|<7k_mv{xUB9GA->gnURqBE?iOfPB(o#bMkxDRsjdX<$Jm1m4_5d z)D-1A`^J2DM>80L_Rsa_v7Q`ggem^g?TeudZ z?Na6zR@>CY&dmc|#jdTPtf(syS>!E36l{{bC=?IwT@5Q{wlLzJFn0y1DOz01i5Md) zWYRMLdDT>RzN%XWMQ9-k%F?#=hVx_LqakL{Y|sSy}VEGnE{-oIDm; zw4Tq}qhRZ4=&5A!YBU6@e&9gf!rK}b4EtxHvgkpP5=G-*^(iDnCsziTgxDaPvlyn;^wTGHF3!j7 z?5yl;oh+SfT{Hj2%*M{f(8kin)W+7v*v8sN%+lHQ+4WtHK8`u}YR3eoyx}IZ|AaQL zHL7Jjr9Km1T3*zqCveleZC>)OE*rp3y^~ktTp4N^ZWVQva?(?$tY)mnrH-3VbY?mi zNE)S5Ty0+WyF*@jUN9ST3-xM!x<8-KT?hTjfu1jOo=)E!?cCl*Rx_Le9)l&wf-8C;I}p84gjeYyhg(mcId7TOVJRm?IvcDSlu&Q5|U{T_2bM-O(Mz zwbTQxekLs8JAEPQszL!fH%WPBr_m@WcW2F*@)=`D=GoCAOByQ_()*~17+N+OWaWIb z`q@i?^%Lm4&Kr{yL_I?xX3p8HYE&mPnNpc3uUac2UG_72t!oXkmm1Kg8mf?Ta_C$Z zaYicw(Y!rO7b$_f{${6qT)T*}&`W+O?NRK}0nJSYw(u{6D~004;q6hMp z*5%hIrj!5{?xfZ=^ENn6AO@PRQ&;zrt`C@U8Zg<)PZK$yZ;o|o_u5`_3RVRc0i2ck zpSGW!GV;nADdpo)GlLeTLGxm-BQJ52Mh8_hGIl zqIB?x9wDqx0bCJcb)%?)onTs7V7%@4r;^rtY0{b}9)^O9p%{U?G`_&2^oP-|HHA`C z+5wDQ=zejt6b?tWhYM$%_Wrsrc;&wv*jauahsxMp894^Lcdm_=LzvF0TZ%mn&MeVs ziFwKx_|y@uBz^Rq-+ytu+d9;&UJ1X{sWb(wJL5yhtl(Ah;-!6I3V7r8E2#^@UA69f zJPb#m(OlXS)~z?dVme>`*(GSh!#0HZ9N-kf-mtnNd<(~8mP6mH1ULkS`-p~I5G2A~ zxibioc)wdoO?%>!e^sIuHlT(bVa7bKr5?k>=nNyAo9~rS!WOH&wodX#_=Y?(7hdG` zpoeA;-}}?$2;FfJI`8jIKn)({u>)?k3B3P{AXBJu06Ill!xXh_XY1ui#0_>`6S-tI z2Z%%w74r1qnqcE+>O9m4fUa%uB--M8dP@`Uf9tab0Oy%EXq+L8`jlMqgIdW3gx7B= z7c>IqClf4DB+~yi@KEg6EfR7|-P4%OZDJi@0SUNSSZAkkmiHxAJ)#~~<`QOu{IUAD zFjt8yWdwbMrei^SiQOXNxws*(NY}LmHkcm5>}6pMH4T*UWMuh_hPxKM__S?VCyY9_ z9@{M83*G(trxOnyCN1)np0a(-BCQ-Yt)>o8H^Jdt-SiLoxyUF#1WcShozOSvd{PlA zS(p)zdF>M+`Z^`fbq?8|*1nvC+go8qX=+m%B1s)+i$6zFvKZLuL{q~%$mdP)qF-$I?BU-%L9!DbV_{4|T?gk3 z^5vyYsr}3)LMzTMb#{v8jD3=b*hOHenuc}vpXg9*ZqWu|gSC?s#G@FOP`bzO8hkq* zx<)JnR3|2(;6A5?LUu86eSte4#2!dq=dr24ZY=7?@F#8Sh}rcOljhgZ_cjo3OO2@C zQ68Ws2-$g0(f+RV+*5ox3@!kV9_&*9VvZak;zp(G%DMWrqEpHKz~vX#gnx9W9yaq+ z7TMEAOe^gt)AdSk*5 z(6FV^2gBA!Z2y2SC{wvi?J#JqFAAL{mV@CfNTX5+{CsPAvum5+EXAcb68tMw&k8*| zw9(h7)8In*lE3^L>C_V0!vu&RXUftOk9aJ?(9ceJ;<02ejY@2ik4lS=~Tbh-{cnU8u-0g~5CXJUu;>IUH1ShI24sth zRV99D_2B@8m{aCf@g>n~SA20BGArfso?VB$!py>-l@`~8VW%Xxoi@_Wisk0H`8;6_ zBI(VVS<|u;U`(4Sw$wma$3;put!$kiq56OOU5xivg0(D+@TtJ=j^wIVO^T*`_{sqM!F;znS?6}v9+;>Q|JO!pREn&N?|@zIEH1_iup2%AoB4DBN^Fm zO3I#!ROIfG?x_7UVW@?^x>cBTXs57t^9%NB5Qj{HHeoLzKIE&U+#|>GgXepwuM%li zP%tz$)nQSWC+?Xy&tR*V4YfIgL~PfLx!W|;StsDpM%b0+@D-@~8B`ndBq^i|ODDvn z4|V+HIPg@%CqRr~5CiG_F_Lt0MyayQ_zT@6uIYnRT~GtGpMXhDC|^aD7b8-TK8A|@ z;PltOIh2CSK#O;a|Mibi=AyvnVM7cT`v-;Bo+KscNAAAaT>X`OxzLwz8veB=;@u2s z*Qd=?eSsRo*)+)J_>XV6zZMMu}b`u>})j-uNe*ONfMA* zURj@+kWMXs6@;KyiTE1hVz~i(Nw|oLi~PbiNggRtjVLJD2k~;yC%K@$%~Ua*e~HPb zpG1E~f#r;rl^fUzcB7Dnv=Xk>h~55h{B28^_ zBK+sY4pH|W%gP9=IcXC64Cgpz8Gn)?uJn>p@AzNNyi*^C17*>mv9VhC%4FbCQl1p}b^~%$XASjhRFJZg6u?pAVY<9Y}^> zp{SyD6pSrSD{mkQ^97+JMP_2T6aJI~Qiyy!Ja$}7kk3m!{WY2_3O>#e;S|BQPl&*= zd#vGeRWR9I70e~YbySSbraXzuG%F#?<={ne6Gq(?GZwcL^ioTnMaV=B=UCX#2(3QD z(T$ZwZb(0UkMX5q%m_vd(Tt&lE-RSsw*c%tId+e1L^MDoP-RIX&?Rjo!Xb)iK?{lq z23jgH8=xr1USnjuHSiF*ex~Zgo$S9nryJME{4kBM!ONfUzDRnlCm*#-;JR(`)wp7Z zEYmKrtp-e%*|#G+C~}Cu#Vyp1jWu>j9<&bMBY@54kp-R}p8~KA`h#kfnlr8qn96Kw z!M;b4szn4FV}{ew$)m{qT8K&XdBXknb|lV{z^47XK84d21$I7#SI!--s(B}Ws42z~ zNkL*CHq!E;|Kjnq^@o7Wna=o%gXt}%{4OMK*wj3X6tzgw%I|a_@&qC_l)DRPz|(e6 zSU-~z12gNI)v<~_0lz#tKP?DKS)v?k-4d3ZI<@%{vZGNv-;4sN5jMF{nEn72f(M1& zVr{b2pz)P;J&yH ze+gQQA&-HGH0hmRv5imQ8Hn*CN~Yu4$A@BbC~$_MzSH53(@A#`cC+*kt0q zG-QO)@E{4OG~EdF2T^Oj(zj4nVIAaSYXIzaL)@jy%+VoZ7O8yMW9`+p)W3UxQ2Y>a zH6fS76)W@9kBwibA0Vr`U`{v#G;v0ET?E{B6tQ7}Z(yCOsM%8wlB85MCC)9#1~9ZR zaG2W&+vo@&Nlm00)|NuyGc6t?p#IH9*#ntQl&q1keTw1S;v8`z8O`Fj@*SQ25mo{X zxEkd|#?b{h&VtVwe%SQ0WTn2(o#Dot)zRNsDmrDVQT9 zHG+&U4m9&Zb{UHyHrY!IoyL2{(jw9#qH{cGQgTnvB*tf|KYe~|#r z6(VmlW7<;<&;|DaAmdDW3fmFY*7Ctpv-2PvT3i-{8!xz**{ve^hua;VAc(dhq!rPs?M=c%{ zEoThLigFZ4nT*GEFL33ns>#2A)YYiT291KldQL@~bV?_Z86aIt%bg@9UyY6}%nckPx?6@+sE8m&Ux`LqM zmZZ3bHMZVS(34*WVYyQSfiWZ#UOtEgd(Q#62i!MlA`s3)68X3wbKkB`Hm|2--s6nD zkDUuK>2=)AjG8V*3WBQEBd8lNBK7$p%#oyS{9@>`3CBSbEv`2wFU}zS zy=!uj)1#I;p}lU{g(Ro00EPzTPSDtBL9OB-hF#hOxDlbc1+Gv%@>S8fv$7l$>tn zm0~D#nKl42@87klek3d!vAFLkfq{|LSpjNwvRf$d{i?W8j&fHEo@xEFYw(bsz#lk) zR-!rxp1+Dk^d2dFN$zP6zUKhE>ReHD5`KqX<`k6?&KETU5`$?VJoI}A>t#MAz{k+y z!wgp4&m0_YMg@I_*;g#hzRga()Ne7t1L$ zvEKVnUsGSN@49YE>KFbHoks^op;KU47FB4a+U7L+?#c9cWP#l#E~=$7oG7dUIk4gW z+EM6H38C<_W6C+~YN7l%#~*#64?G7`pd%+^2of%)JyrXMG+T&oq9QcfCEP)QbKFLB zb=%nEakk@vXw5#hUFbkZSw9f#hAcz}oI}phePpa7!BI~rn20NqA!UmmCw}q($=lvC z2943ziU8jLvK76;7hz$zfbM?NprBuxs=aO8imf6dPas~b(P24=2a>eMMwTLG8dLZ8 zAo%(~izYb2TpRV&G%XZCa#n8tph8oeS~vppIp8f$#6C&r*TDh7A6+DIK6 zd`O~&j*8T=^!a%~G%Dz;VOVVmgrGD1{v$gaX`E#h2(pLt=K5Qz!6cv+^wuKFzc#S9 zsj23u4ZPGz?xa`CUMd~ENwfz@s>w6k(P<|by{S>d$KyqLmnoebKH0HMQrSR#Fco(h zk$pJ~a9QaTP&essJfGSO2M57FE8yTcc6hRZQBT&(x;vruKu zzOY>zY=3MiQh!kE6C~JU>F||%1KN0V z_x{pm8p4R>8DQh!#J}2)iQygTqq4q2jgP^xXnYf8E<)FHMksL|1w-YD{zaM3YNbuJ zocy_AbS+)+T*OXLn+d?Ciq@ipTRJMAOmE46JX-^g)YthlD~@lOM#gf@{;1UhWiqt% z&XCKMCAF)>8LFMbU|jLAc2>Y^&^Xf16tJ#(ERKM%X@;Y;uqNz$F^{v(C1~MJO71iD zgMNhtIDQiomsPFjI)oerqde6-WWV1ar6ZVB9%+hv#sf#u9=-3GxrSXmS`uq@d0J%v zp`+3aiC`LvlBem%_K|RMU-T32q9Nz#=Lk;vNTT9+I?$n&8!RXf)}z&IQ$2C+2!oyU zsKXrV9Pnp%WC2JE-luoezDb&mJtS_w4L+6!O-bN>S%ThsHmz8*1|O=i=Bi7BiOIeS zaaM626j1XYzyzPs*N!CO^DSgw}aYb zr*`+RTGfJjthCLlqMdX44x)z;P|NDHSYw3DYwwy! z;|5;C%RTv|#6Z(e2B<~-JTLRMmT-QVoSV1`aShW1*U_ox;U32FbK8iLcQ&bY;^=vE z`Qf74UIS0UAZaH=BFzGOWuYt|@H0xYKIV`HVp#^k0DX3NLDsU964~Kmj5JVqV!FiW3Fi0vQn#3J$q`_8jJ91&lB#A z;xz5Bl~Lo=l2u~~tfr+wKqL<80WvRthL{Vp7GN{dkFzK3)<-B@3?Q(5Ir5lVfu8KGgdSgdV;(!01ixq5T1Njn&J*x~lxRxY(f$^xsNKu1EcLa~X%em<1+0 zb~CM9$|z!E0`(re@PwHuuou5BPBRvV;&2pjU?OXVntxdu3+f}RmJLDY`4_@V=Cp-4 z-dDRpT8Dp@!ZomQv9>XnsUBeK>>^?`k_XCUH67*A{RRI1MDv`b`&0QD?t~9GHq{Tx zR6KF`FZShGVSY-hlPsD$9XHr)&a-~aK8R*{SDkH*tEpnl7UDbGDCgHr0DZmqbY7^L z-t5=eihMZ;T;&H_=m~PbZyK3&U3_Y<>`0)pa#@WjgbcFApj<@7Z^@LI80&+ax^Qw&H5VF z>J9kEG4KAclBnzypcoB+bTYO&y?JBhT@<@=1P|06ini%XPngaigu{>|EZ#|+$=36} zKvycx!hJf@-qfI*Al8ud!eV6{dhxW_2*9-K4uuBu=BY-IEMJ&oI}q8a`t6?zi4C#ByAI`?os6^Nxd|!597;+G~Z@y27_3M@=vvR|Ex6R&^H^nS5GQPb!QPWij zy#=SPzkL~>CerX5z1+X>?P?#`aSFn|Pv>vtV3QH2*h}hw1;4Jkln%W=`e|_^iy#%ygm_ z)=nl4_;jMy22LizCPsF~CUpOO0iT(fjp2VnJi!_e+Q?!nwQAc;d-YU<`|)Q3?0^j9 z~7r~5o7s0_{Dz{*SPMQ zEf%{C@RIaDIa|I>!8+RMes8wy1@X~01>*niLok<~k_CZx*Vn!#+zkO6`lFrO4ZL=z zR*A=?BR41G68iah>mj7|vH=XoC%WG@x8|yXj*Y~98#6*9_zuzEy$E_6TE50GMwsah z>?PA?!?fIR@G+S=;621e@{}6*rPY4vo%O9H^KFfTXBDqf+cauCB>5HMjbvv9KdnBM z=>l^9v1{2vk`&F`Mvg)I;japv78VJUtfd?|+2!;JmLd+(B&yQAzzrxCFMlI+<)3;Y zXM~t9Ewf3dNm3sYP(t?~c@YJXvOXPyb^3jWLqLxgwAX%z`ksdLMOCC)fGyH4LN5X= z=7Xa^qPTX~Mf?)njGt5+al}v&pN^p3sZkxdKa~;}m{=n=u})wlyLA+z6n-E)>OEh1 zo~*|es}Pn{DQnog1u)stQItFoCmAO}Ax2Ay2TcgCCcjxXU)0pd%A4aa$`St!q>0-s zuzu|sg7jQ!nrXU~Lq@tc5>Kk2)GOg0diu)d)7L7gUNHh)*Gu z5z>rF3OM@3gW&@|)u_^@x?@a0IzmGS<&A?5&CAeK;5&v?s%bp~@X(Qm2n2Q|&{QY0 z9==rCZ<{0MM!*@yIPkbfx{n!CuBo8#Z8JSguKkc)uENdBDc8;aQTJBeF0iea*ILs8 z)~sq-Gx@tB*nn-$vCFvLFyxSH5^W+C%gdAHChZ^3gPgFmlC}+AR-Rq$%$JSC64mg6 zoY26?)F|1ChGL_pwQFo-_dPbU)d7~ginV{FGlLP3H3M1NQ`?+P(>&*{jwPx99^Wn* zuV>?(8g13pKeF8oQ<`BrK%qVFa6#2khI@wskUTMnU? z*6^(hKPcISkBba6y*?WDsEZMURNh^lj)xDBW z!FNEH z^!Cf&o-WmgZG}j1MLVWu&7EeTZ zc(`FovR%XG(0<^6D2QF5nlRFixf~bNH>~1r=y~)U2@NN%AF3B^1lEoL3s&`jtI*WT z#wD9<=EtnW>q-4kpC0c!n$*0gv`3Lk4AfaP8NwpSTv(s)^UVVeSMbAvFVkR?19|tO z$K)s}V>!_jJkGkJQc}C~bQmaVaGmPty``T-+I*Zr)=4IQKdy=l#lQvIF`mX8}1vt+zf#O-uKrT7BfEx?)nE>qcx_eC?>X(lL~k|2UoM$i}D|*m!q}t8q_2M z=n{dx-j>6On;mh!?{Pl8DoMP}5oA{7>8wHo+q?#Kt4;x0(%>q>GtICmP+oTA`}gU* zYGS*IRoIB)AoFHDdw*KtUF*9_#*(u8HDJ!Nn9v<~y2kEi4SIlnD98+8S0X7|J|`C%DyZr{LVPo|qva7U>sQyH+Z8yH1!k>B7@u{Q~f6UTNU_u!gw5bI=v?zQ6(CE!JF}apkJ+9FS zb>wuFZR$@DB}goc~pImol=BNyMocDW6GqZ#6n$+*H9?Mo2TGrnk z9jsw8k{WGPRlkeJZQVBCODXHiBUf?kI1y~Pfj2Q{&ICC0%knq8c~QK)!wF5(=yg~% zNMyr>q9)D0v4W~(^6DV|2SylNs4W6OHKF^3Lf60KhEQD7Ka+E^Sn*n?MR?Aryb;CS z;bT*h)ywNHGleSygD+VZZb)dLf()^~lQA`YJ+Nj2Gi`0GRP1UaON{QeqJ9Lb6qES* zUf*{1a;ihwOFUhYUcq?G^#_i}wkcUL9C*(47%_jnU9jt|(GE)yuxP(~)8KOrQ+OOr zU@q_j{#nI;pVrP`v=|NKuCuSmxFM4b6wY=7ILAg+RmbIIWAVH&rIgI)g02zfXASNu zvX6%^79dt?2KAt|r#$n7d6-eYG8`JS44M|toUG3mHnq-?fRfynD$MDgT8>85LEUwV zK0JM4J?hcMnwR%Y>pLmFdM3S`fF-pr@Fx%Avivmj+Ggv^85Mc}ub1wu3d5g6$1Q~}@wT_0m{29!LvMAwsbS%9ez|-d zXS%wYQT{}bxgIJ`7%l`ocGOPK{mtTKrT=#GJlt3}GG0nUJ?#tWX8}{Kn3{{jO>d=Q zQd{#sdY{LxgU9!qG}p4T8p?(P-lme8|2m9$G}=L!R%o8vj)dxrjI{BfbrwwbTMY;W z6GtWLx|b>y-4irn!s&b8m+d>=C&roB`S0*Xv7sYx_It)`4SSW& zLOS-5GcLbw6Ne{yxFE%9duL-u06?kQ<%r7DTH%}AnkE!4ERXKQnFsG5>>R(nJ_k~Z z(Kq-XcGJ-~Ux&B5_4y_KpR(&U@`gf&r%O>r@!-d*F>X$U@2Zfq5NPqR4@t~p#pw8S zTwX>C;ihqldBE^x;;*<2V1xG3$4zzkwpBMj%$;5H!aXg-Eue!?C7{>gy31(@fT2k-1ZhHL~CR9frG(O zaxzD0xm7)CtS*J`(ac3X{Q@jK1K?gmq|d^ttKx5N)2)J2j$$~TGv-#?`yA3lP&4+zzJa|Kd9g{eh*jOZW!q;PoAcX5_B=OcS^i)> zjf~vH-bw;;+AWt`^8SZ`h^0zx=dkMt?u{iUr%^U`92ud_#Accz7?*;th45_q!%lOi!}q3EoJ2e-U`ezNdv3 zS$!WG(`wt&9m7QS4loZQ^zy^*!aUlPp7RtKw#3I&B7OPRULO2SDDt7V zL$-3uXfz$GpZ@s`Q;QH=``W$tYsiE4*$KpP_jilq!3jd^vh%v@TdS=}`tzGXY2W6* zuNXbRV>kB?&-Wj9!nQ{u{T2tiG3U=Uidw?VesVJ3ic-ax@JMg<7-(#EMegOij(Pm+ z%QyY&$}n5Qvy#Wk3osk_AH4nLH-11Rjkh+tUvfVuv+uL=TH0CK+M#3A=-737wjCa( zsEf9`aqG@RcU;#>0V)<#fn~OsW+poQ@)mIZ4Ny1M~5!bb5m2Zvr|)L^|ADDba#BZ z!5-%ihW~_04>zQ;fzb^NSAl&DWxNN1_P0I|Z!oo3k`rz|r1qgIYUoK1Lm3E}@A_)O z95ZoM;f-&klI2p#P9yK`dc56D#H(HJ0DE^ZJE|8=+M0R~727#LDn<~=!6eT+V(4gW z6vYj?-0_X=zF`VG<~6j}s=Vt_uKwlN-mrXPWBbC#lLOf)oLYLFqJnQU|K#Uxz{gx& zpi~M?*iw@+E%a zFkkqw;j|I`(RiAMIch)IbD^Q2|NB6>mmEEabNZomWUv-XDC+1eq-WerJqWK?9kO0x ze07fD|C_XsT-4twp)tr>AxffV6w)*fo);wWZ)!Y!by4O~F^kd`mG~v2f6ol%4kxTT zHuOunU_IDBJgtB9-hALuHS|Ho(fuv>fyU($y_>iC&csjJQ?2-xnJIN786-(&mq2(EpH27ZgXxz`CF()V9< z7{TnIFH>}c?|(K3;e60Tc|Gzw`vrFn&;Q19SpIL8!^FVO&h$UR91aG~|AaZ$Jk}a0 z>P@FPH<^JJMZ>}@Rwg*$Bo!1K1c#r3Ab|IX0t65b2!eP~6%sK>{2)OLSa*Pe^iI7X zkoR3=j1`(OL{v!Viv@_n5tqb)2&THD;LPE*%gYp9ejA^Ef7b2$>zcacUn{GWRdvhf z&K)sA5QXZCWg~?9Zf>G`lI8f$1SZ^Bw{ailYBp}%1l=qhdSUAxPib8oWURat;t}8i zto!de8b(U31Q(?dx~i9iV+V#9v=rqxPBW@&D^;R_`lY|)T$G0_+oZi()S z@B?#-55)G)eNO{v&IE{y{;K^8;J9pose>mh>FgjPBEe2 zkamZ@JjPaV`DZr|1c9vwX(+&+A`o2AbsO%MQrB>8_TLH@)BdoN6R zlLNo_zWz1hSEnLaKu=f;v>ii3tnqV$o-j>etJo5uyJE%rQ=pxM@JF#iDZGbh?Zaq7z&OBngfgikpg`J)BsBXdZAOOlpq$s5`_YzM75$4 zz%VCK##RxCGwH&bLlb2L+sz^pWsJO#gh`&e??E&2$a+%;9x@<~q z;;({gwC!m1iT))!g7T2{*Cp5Gl`#D{mZ)a$} zojH2KqgxDlbdi*#Syd>1z4V zwF8taMR2yGMeHL!Hv|9Q=v*4kR?eG0YbasH;a*u`>`c_!gjntO950X*BSNv-&t5!n ztHZ8dud=()S7*UB30Pj^+}xaS4J`@P;aeH-pX-%giGzv;%0VIk5t$&WImpw>5@4xlEeqY=s;aK9HnfDp zY$|@(Z-RC$`Dup`$u(G93~ntFaH0}8MT949gwoK?M4JaUy&eV}Hh2C1)OYarzFXMF z%HK6M$oF&ooPP;H_;K#+_T%?%t;%uN)Y5arajPi#XcPy!c&1?jZ=CL|FO7xq`m#Yt zJGHW!04Z_84GbTrp&c6NO#jijwV#injsHD(1)o*%$FFV-HRrRHo1T~7O3I}Ce8?C} zYg^DKGCD8r-z(4Mz_cH~bev-tjxzpy#s6GB1&3#xZz3e4+t1XwgGs4q>Vy*BGBq+< zn8NzbE1SGRWHjTo-(nut+;ygD58d|1McU5z+1A_y*bR{O2}LlUV4JCIKvr|6l9MgM zHhlR#C#akLh)-aRQk{YSP%h}FUj}E!3kye4ulg>yL!9~R zH*RST=<5M<#XuOJzd3F5-0yrMU*E`?34;iQR?RxZ3yN7*;#tp@o~o#kkf^AT;rO07 zxbQAv?;)bq2=14>Td2P*L2<&|EvS zf>RQuz#IDTH3R*yPVOhT(>lCcc|d;Y;7Fc!%dBIwo7ZiP&1spaAXV%*)%Oac*)*0< zcZ^RS4eQRoos>p8Cn0|~)>aPGWMppoJU<;=TN@ke_64EA-3dM@F6>h3$ZbUDD~*4d z?vJ1CLfBQnVWZ_xFk*gik!g3YmL zD+Ox-{(SzHZPgIAI(vGVq|)JW~ZhS)Ug^)O-FB)h1yCvonZs zTRhmf(9snQxlN6xcFx?)%k4f-i)l|X!?TL{BDueB&a_(L#l9$PUd>Vhkwon?lQJ=B~5xzmYH9b*?OmkX*8%7^RPXT zObD;jGxPFtbMx{hSranlH=WTwjM;4>Q`blHUpkkb{=UYpWhYed16;MCJZV>nNYi@z z1gulU%m>3S?D04<>~D1(uL!n8vl(8-QO8rgUuT}9eoIOed|f&t>-2-M>ojuSM3*n- zTS>v;P$3xsV_HJJMGv^jcM za6n==0DkQkGg2=%QB#knlKQ#@;4pe55qCTF|I8#1wliG8!}bsIaKLbx1;QyCn!nrZ z1mz}S5&NM23oCWR=?x55ReLD(0?&=h7Bp*XT09sH5D4bZL>wz;>NHC5n&p$hfHwjK7W6)9B*z9u+qe0_ufJ&B0eb86 z8(efN?9oUAkn$)tFtYnYPmedj_;&vh|OfKts8%ZAXD1YDbg?@h|JgvbIdFRF;J^|kL z@Ur>z;>S$1sNHV6mDOykEq7Tw*S0z*S66y2_4oNQRy`}~jPyf2V%wAl3x3%CfU%%C z>f=6IpqycuWqt-xdKjA2_)pC5^ydl2Huyr}G9Et) z6`0B#=B)>_rI}qOI~}L(kiEP1wSogkOWr20bu3dF^YI0K50mb(aBa;FhYyHo72;<~ z@B@`Pzvp%8RKO+#3krHK)N>S?y#&nvIx}_I&+;HK!*q{EtN*xg^6K}a93V*sv35m$1=ymSVK?j=a2d*lLhm-4bhghkDSd^UxJtvQmC|r zgoM*~?1vMZv#IwvWp3fycd2KoD~U>Y`O}}#K_7@^Lmkx2-1(^tSyxk=!*G0DUap&g zsVF9$F+4W!KP08qB{VdLV9N-AY9sfBL!aOz{53v^z-OHs-T=xB3KYjxx8v%bmp2>PBp7GDhQmwgK6R7}psVjRKBd~Z(0$E%9E`tlLmJ*Y0c*eoC=W#q^%pXtqACD4 z3X>=$l3m9ZKuQQ4Mae94wL|&HKzW*s@uiYJBQ2JUnW?fC4^>n24i_EH2KHLb{Q6$WcFLa*p}^KwGIz5Ab6w& zZ=Lp=!QMeI*k#VVHRpu{p_lhzb?yb21CSJGo|^BI1*ilU&LPw|2-DGzyi2@IV*7)` zyZ8mJUN`ifVFl3~mv(3!puYEH=@9*vuOBG8f9B^pPCtW!K&J8WZk_{CVT%0%FsjOt z;!e(FIr=~&2;;>ext|&xTttu$I6x7KEdwxmvH-_58O9kO0J|Bz&_Rb8K@f@+1Yi)g zqZ%svEBSHIv+2T&Ybsalz?8|!PHLW-|l}x zWUNfAZ2yVKW;xw;RMb~b``B;$2FZ)X!ZF0m5df)mOEfIg&Weg6jBpJ=N;*-rb(H^L z$g(h!>C5bx=(4I^fg%p#v3H3TmuVnrM~TH|9O<|nMr`;5l`$lHJfj0%T=hac-`WPlB1 zEqfS=^*Kv5BhMN^=7%|uZ5_|Fgnqb|{cwG_&X++x<0^w+=ojYeyZKE%y<@jH0NnNg zltuZRK2g$mPy}XVQt9o_xVKWqrdaTV`qj%&($IDGBM(LVnuELomK6hS-~DcL7HZDt z3#9e0pz~=P_La8l&%W8fcIaob47z7lG!8WDP zs0IL;Sr)QHjRjk2v*8WFaAaU7vYsR|QLsXOB&9H4tZu^n-T`V@5&Q&uTwtArDG|nM znLQNzcnHh&&KID@T74pE6japF3!4vfd+q&!5Dz?WD65+n-Hyy-mFwHM>=r`Iu)c-{1m`h zJXy5)*Z)zF@*y__Lt2AS{1kwK0aBSD(hJr#;MJ7~c4`!aA_RDEE%VRl>=Wbncf)3g zCJ+YL--=fh!4g$;!RIhfn#VOqk|kR_XIb)=AfiCu{R}Kog$R!l8bh(@vozICwwQI0 z&q`a^Ig4@Gs&65XqR5ayGF^(NY$)dQ71n=MNN6G|coM4%W%+i`9Bnnk@ePp*J9PXA zyl5224T7Mn&(-ly%Had!9T52a6LH=_ix!MvehB{ngO)RmC3_^zHw+K-{IF0|)tUij z4{S9B7~8)w9l(_ae7FHb4!H7tom{b}?Y*+w{BV3QGDr;L&AXf)9diR6L%lM-t1~;W z8}B=#S)i zWdj&Z{&=D*$_#M&#G2bdC=F?)n-Hj`E5tYMoRDY-Si1q-H_#jAR2nl=c?NK3gFu?F z(I&tvcpDDv`6dm%>^ZaMP8&w=*xuQnAwCoAbvd<3xQ5~@VixTz@?Hws#5BoUN$S$)B{Iu!6-wNH+$djK zUsApFa%q0aS2HntTF(iaQvfby_}GF|4UYgmQTfQRNqR0h`Z)8U`9ZCdiLG~nbpp@#-Dd7z{PwqASS0MX6Z}Pv+f-D5)jzB5`0yOe%>;Imj&{NcE%oG-Q(8LgkCPl5Lozl4aTh#$S(teTlk)>aGTE?D zaRsDoj2w<&P@ILp4W1fwoUG*xS81B7RP6$#C?}|9CD{BQuy zYiD2+7RE%g1QONkA$9Wi~?cqdh*?kh|G8mz@U z)OeNH&NFrh9bHh(&{$gyjc$#^K+QiByosY@D)+!Qk#vNa(pc}LJ#Kt;EsXO^T6v|e zP-lLbW(?V@1tTr~pQc#{VVJN9m}4U{!3Ji%jb>d@P{C4Uh{9FUW#`{XHcSAm$xzbK zPh{p*d{lFpb!#SfKvue(nj55l(2g)dx>^Vw7h7dDY?1NwIZVY8<4&2|jK|jH_zVdP z75UDYeR4=Sm7#)tj2<6+U>q9ZA+M;iE~a3Z9;;LMc0{92C2hbY1$PJqr&;#2TUZDoq4x}-h4Xi6cashtgi$P+wN!wr!&>7e> zaY1iv0q6$y0;gcFcQfS%B8;qqGo=9MzBl}f%EO=mT9;0zDo94&1?|#pP(?DOY6B~P zTGxtvK;0rxehIS5v`r&SYP@C=Vdj8{dBXu}!=`v;?9#viYXhe!UR<1_IQ1cE?1kYo z6IdE!R-2`uZ1@I<6nGDUlRE=<0cjQnAjjZ_alvRNhWTK2Qz=3jk7JbLZUEU&8TpZ0 z<1!$}D0OyAQcNmlPFF(WCLXQ^kc{yq9M=540m+}d0$R4`PVvzLmeRUI4=@?)OELgy zm;D$EAe1r{hS0ZkdCqznWv2C3R>^#XcY zO{PEg(*W>#p*2mJH^fo^TeEjd4y;p6n0|W7tPO{RUPaE8S&K0ED}^Lh*@@j*#$DP? zAvG?3V1LJmLk#^(Ps+p_+Gc2*nX8luZ$0j#>3uTp)c}g3M&Fc9;aO{Dz3$c)th7$2 zHs{t1)fS$#p{FKl$2G`DNSsfEoS)Y5NAZHhHLXiRw^Tq%PgJQtM)7RtJg=jkMNgZFU5Yc{TTn4yUanET{)z(n{o-oG>UCB!z;rp%PTXF zQ8oJ|^CcTD1C9z$3RzS+i;6f^#WaOUOHz4^!Z_7&%EL6!Nwl*{N4f7H{ywb-^>&Wf z6D9tHu?PHi())h52mW^2_}wIL`tc3g2T*@P|A_ux^s9!dvdKybHMP15t9+~)(yC}v z{<+Q z_KfLC?1}8j>jF0k?i$=hzNI)T|7E__ILq$O(w zP54dO>ohm*PsQ%#r^d4DY_JZR_H<7}_de8Y>NmbUvWoM`(H{LUDkC0!t>ry0$UPOk zzxvVasM5oan~?O|vx>dmV7+y4d(1b!<4CTr;npuW&p(x?=|gtt)SPaJm$mE9aaxUZ z{)Zhsla+A(jT=$EE80Cy<0(gkbwh}7&~Z-gxwfN)>u9qWEt`Z!?*aU9IH*?0d5Y=_ zL9+BZ!t>SR%AdWb1AREb52Dn6M4Dt#BIbxxN}^$|NQ4>|3?)LDB3mPjA=?U*;*mwM zZRn+Nf=-64;Iwyo>8srB;81l%Ji<-D{r~5K-45Pm5(|#QnEJ+Oi0H^wv;} zu)^^7FG2ipiGN_nAa4YazT?*uCD8d!D-uJ|;ZB3i#^bLnkY|ni2F=!=wpnfb&WrDb ze+~yc;(j=XqR1FE(EFux-*PWU$J54ysvT=JVh{RZP!EhcHKM0QGw7l@s)Q}sV%Q&o zOYtZ31FlD;UVpqG(h#lG-6xRZcC3X^Y$h28u8V0Z?*|2p7^0#xvV=_W(1*7}qa;XG zdm;%Icrze=beJ^;L584eFl8`qyTPf6e)fDGcL+-y;lh$LZ6ql)b+@ogPp zy`7BO1g$hfR!H23W-rf<2b!>&6&gBU$6BlTK00X3XQbU={;oUb1uzp0kP!(5g@g;+ zxH7Xq)89g7iUNDftasglcApJ}?hSS4Hn!KQ1%qlFg&y1tb3kparbM@8Xjzv}dqk^U z2IHV!9XOCj-DQEWdL5osR785uZNxhAtBw>189lYGVIQ&4y$(slO+VG5kBh!$WlrJH z5p6T0CJxZr*~>f+kr-Xfsi!%ytQ=8ug#1nB@}haI#}r=gyJ74S-ogg<_eJ;=Xjy2+ zTAOXt+f;1)q8(o%#5nq?hQMPAug_vMGf$Cyb3;PGAv!4ocyhN9z_-@f?0Y<=ddcU~ zrzJ6f8FLY%^C2FOqt7|W2*ws+_&s&TsKC>!LhElOzHXw; z&KQm3eR?0|RV9~Kg^7=p!$!PqpczIU8Ty?gwYiTA23qIj=H*{mWxu{NH=mBr*=aX@ zcw@)Km|EnTevLXaK<))a&La{5DJG#=-?~qb%5nKP=0v1nn^DA9m{KfH{pPo7g@8|> zxvtL_@$3|SyPIrYdQ7%)wCs-OzjfemOg0WjupvDZ2}uZ{DiYo?hlO*O?3s{sESXQB{mM-Oe|h%d(YZ#GZH`Q zLk-s*!nBEd^D5H7WfIqQSlRLbk=^kA9;H|G%FA!#?Wq19<&GJT9IwvvL>hmZ$p z%*v=tU{$YhlM?Fl`9Vb!0EjnQ@f#hX2j<1#o^|o!reLF=^+$8wEd^SyHIOr;^^?TpgtT z*1{`TE+8XZ%y|UC*ARIOWu9m?9#SAxUB!JnSxjBmo9O%CaygY!kx#nor;RTSC@~5y!TN> zBBWb%1WQW(biL{ow>5tdV6n&0`h8{#^?SN2)az)w#LnEQ{O{So#$m+X+HSR4zq(#$ z6U!?qx0iFuNfS^1{;ac{e0pK!}xzG(TE@j6%V!n3&W z9=|cQ@Ards&dCbgi%Y0n;g||Ga5@p`S;)5KTQAoY@eB-3g`lyJb7EJrI(~=N& z6huYz?00+5McNZKF^c+!Eh3>oJspxmsF;z`sI$Rg5pyYj!*xx3gAxzb#;S3atpUA!a3)rf5^DQtEjL8?$k_vc^V=~RsLRfa21(7zBW`_~ z=OG2D{vRGfV(Im(Az)(F>8D}68zCENIl5!&v~SO0aJMJUdY$#=&jnX|8>Fw^Gb8js zMxnBiP(Yv0F4~pPRT;T_mRgeTKXg4_6oQkO!ofYX^MCuwYcafFNp1Y<_ulJnmr7xQ z?;JxP)+`p`_HwGD+=@zxSf0uFo8~wjWnM~-5|i1lH1-KRLq14JYYe(eVXS*B(pk78 z`5@24KZoVl&rT4oTz251ngQst==*R2aBb2`JtAPXv9f;x zuFqE&4?W(N<>@^P#x9_9Zk_lEMbod?yrYRAuPH@V-Q*s88% z=T;UoEi2=sIr4iM(u{N76hrAAktOaPJF8Axdt{hgd%Y61eYuGoucyY9UaYE`cJtqh z?Hz$nMoJ=#&NkxO;r%sFFweTxV3iw8ep+|?yS~YuU^yXb93_gJ{&p1 zHO{A`v|6gKtUiCf+RtKg(oLrx5ugI~Iv{}3=_&H9f1S+r?w-+S>7dtEvRspFDhpXM z?muAL(`fbl`FZd$W#qGyo!o9~cY0jCsG7yBtjwHCgqyzg7EuJ9Ydtjc(Xshi0Tp=5 zb2QgTd^CNlA;Q6F9&J`rdB<)Qj(+=4~<+Xt`RcCT^$qnqKe}lod2Ktz>Vfxk~cW1y$Z1UJP;- z!l(iUULY`>GAG%AOv0!j0}~NIL`6YGkXArovKdTNQ56A20T4hyL4*WA@N;)L-yM%z z|23~)FKb?1*O$5~d4~KiLI_%Q zecvYTY{R~+Q3jdS1v5PeddyYo-ey~)k?K=pOfnbp zPW=)oTcg8N;O@vDxK11@PlQz@$E36J3DpX>7g^tZ7lg%rqI6eZ^Q}LTX&2TL)d4I@ zA#Sa%Qm!=>KuG8hy6iB!Ej0BGi8X} z_+=02mRt3&ySKHFAA}Cz$P*eEzx+qp1@675GHMIRN8d>W_!xInha`zhw282?dXIIgnwxe}9;L)*}*+Bu5MY2C0m71aFzPzHWhp zf!LE?v?otXm}fYcJ^%*~V32hrZVJH}G>_oC2#`^II_2Sww1UDvpA5=)JpLUFje^)e zo)pShJh+!fT$qtFEoI<~8KH`qd_n3{EX}7PS{R>WqEk}QU0(QIZup@t3W&k|+DImIdqB9%Pto zfAe3eCeo2Amj!oQlTUMxC~d>V@?Mx$jx2+3ulv6*S#Qt0BPS-yj;+XozP5yRm)WAs zbT^aO9<4X!A~i}Oit0&ok94^!<+q66Y1$ImZA;j3Pm=YNw8_}YGJH$rP4w}}lajQu zL}(UnQ6FmN!*>oZGi^50XI7UOE!edeE`@K2_p~Kv?TmusFl$A}O{e@dfTl#6(|yhG zExc<^A}r1Lxg@mDwMS`cWtb@~vtgRudw&=E>6}Tzf5vG(PtWiF<$ul0P~66e#~sx z5x0sZbW0v#ojf9aeErtuJ@;GbiQMRpIMFuV64=|GAg66_Nob0ah)bn8{`fb%@4fuI za{sEU{ywK-TFiP(F-Wp7Wie$icE&^!%NI?2X=DO1p|8v!FewjbTuRWaW}F8D>d{w< z?wv4`n#fsAMm&&+#S*W=eyo1ByXU_S{Qh9;zVFf8@&6{QdO&V@rYqrn?)d{{>gWRT?+_DQ|6$O(2t09sbzlYH|BGR1z9byT#D5gDf~+70|MS=1RulVWzr!s3;Je zE_iBpY~v2$Ii)s6N4TFH1W|&sjfTgTtU>mRFkQ;vDa(243hYekOv4NoDxtMAPL9}bOJI1tAWr!vOgK13TO?i2kXJTUmQRW)Cc)SxPKb( z4JZyI2lj=FfnWg{11SSF12Y3p16>2_0;Y#G0S*U`gUdnJK&t?I1($>4p}n6Q_#Frh zj1TL>_$ zxt}^{9i$KGNBuUuKOf8v?vLL??V*2nJ4hZhAI3mvNXSSyNvKH(N_b4zhM+!SN+>k3 zLP$%v7XI(G5+Vzef$Zcxs!RA3#)I;tIjT%J71D$8?|BDR4sg2h!(;Y4iD8s_R>9*EmX1)x3E8ZTHqGCh4p1{aXf2U zFc(q}uY>kwehOZg7wU)GLF;0ET3Z+{^bgB}d=3i@6AdQ~H4QrsPYqoO;~b`g{W}~M z9t($!zKT{B<{B;w*G+ph*YML2Y8W3z3-8T#722>ivDFM9Y~*BwZTX4AaP>QP&XD(xPS85`i|nWSnW1Y1%pd5O8cbtuzf4J^s*S z+I#Ff4K__Stu_retv5|L?KmB9?BgNfq2giWA?BgyVd){;LHw0;cXC%fBpw`f zkrHtgF%%I6!B)g~_z+QuNKCYi$S%?%eumgCA`_c|>F7Sv6CsKiFV2H|?=vEeXfM)( zes4LVj;KxK7qyP;$Z)7JavtGN6iiG^j7+plT$@OmxRU6ah%U}1s)y-mdz3M8pXg*_ zZlZrwo7hZz8=ZsyE^&mMNKL#Z(uee}b`+kNFK!q2#pk4c)Hkt5EH9E5Yg9B;WK@(? z+*AZrG*xV)SXVJ!6jFhxSgUxgD5j$Sr&iIq2rtHq=AyFVv}iZNi{DE4PgzB+B6rb? z7;Y379xH+?9~TK16&E8HF&BLoOBdNDqOYWj^ONdganZQg9!{-@yQq9r9;UDTQ}AMR zak?l!axa&c?o;+6zKB2Cx9d~eS?*%L7=GLjGZ_mR7a1iPGZ}vwO&Qx5rn4msJ~NM* z%S=Z`8wP6`x0%z7Eu;I`(>P6xCySZqOfw_>NDtbh+{`#5wsBwV23|AwiNMTahB9Mt zV_@S!qhn)bBWI&%V``($Rl<7MI<=AbSliex2K5+LBX8rfk@@H@@~6PnaHF)b`iPg2 zew;4;r{7iBx@@DivHQqPEH8>Tj~l^@kB)?nijI+vn2w%~rH*V4@l8_4Nk{de*l28Q zH>X_WWmGl_JF%VI_I3xTqx4~3j5g}4(l)l^?Wix-tLk=INB-f<2yP5FnmgA`{@ecB z#9PSQlZUmBq>rnQ?$_wO?7jLJd^|obKV2WKUhHjLK90ZkSML4yJ@jAvSbe--n=k15 z`q6&mU&pVpH~YWsvWTDqjXd20|V}Izm=Ktc5gzvK zw3ZS|%1d`7?n|w9;CsPew~0CGg2?WVVubL8Qq z`@L!$Vh2O$w)a#sY@wJxk~Ad4^zrgsFmwvF_W42MCHz9&ZRq9P2Hw^ zDIb;bBt3~tO{cO_)RlIn-WiS`Q)Vgm%CDq0(jUC1B2$_xWvn!;WUQR5)T{)pJgaC| zQoS^*61-fkq%WQ;k(FBiL{=&**~|A*KmYs*SHhR}rCLe;aJu+kw4DW198KEqu^=Hp zfZ!5>2Ddk15Q{DYk-ArGqzt3}!UrueNad+I!o?b6TF5a5@0Lg*iO>sd^Ao5eT5OSNO zJf1?s1YRb9{lch?yq@+#UM-1@D`c~PRaQUt!hE5mw$27z(3WwbxQjyiSs8vRH}^Z3kfc1(ly)W%;HGrPvG8;JgVfFY9nrkU^mfsE*_*+$ z4sIka7LqCwMv{4wuOtK{_R^p}7>NY8w0R@9!+`bp1h>Oraw;eH`ay&@NjMkfxR=2C zbwm=^%77R9`cwp%tKR%BzKUV}Q(slY6v?AGs+F`Qy?KF^9=8HlDfb>1`BQ8EJB`!-nQ9W&ar0HGoI7ueAfR%x={`b_W3~v6d`gB3p8&|?jq0}0ot@(5! z7o%ZshOPDVNdDDL`|kf^7`LBUdalc3AxCgqTDreL(s3aM#i zHN75pnfI)kUF3{OThD@h+mOJJz$~yvv&uu4LDx!WOJ_@uNGC}rtG1%LqORQ*w0IM9 zj=A@K_H~)4{-u7Dj*8yn80J9DM(<|+hQ$`arshVK_qlh{7S} zqwIs=G4OB)UkBsk(4F0B|3=h!(y8F-?TO=PR>o)Jhr2tOldJ*bln(mGgu8|l(UC`? z&#n)b*DWWPu*b~L)Q|Rv>Mylksz)0{YkvIr(dZMi6M=yi)hh$T2{k8BR}fP9C)2L@ zz(vdhrpAu7?7;r#nM__4YrTPUm@BMTd27RghtK_3uJYF!0!5!cF!5;+2ZkXj-$k7FAX`>HOyTI!Cag@s_~j)dit4du#5|N;euN5fK}+Z-JBh@8<6Jn4)j* z%8vHB0bd0%KeGxMTv`22`QWH(t?H(#rfR9`r>d(8h^g6zP`6uqO>XBnO97;8RXry+ zau&l5Sa#X6%vdywHICmK!d}R2*GbJUUe9>wqM;tv3k?O z8VC>HuIT#~U3ndg9bd;r#}>u*#74xn#zJCK@ni<+=tk+Z6C#*M^j%y-)gYQ&#pcq3 z>9I|8nDUA7Lb}x@=77OcI>#hmjT5QC_jIE1cLvoR8?u9gu^kG?@~rt)`HcDV`Cs!1 z^6hOvJFt8S1)2C}1;@7l_8A37#tc1ynzI9lcYe71Yj#lc*)=3de)TN~d^QCE%QwV7 zXfzj|ecGvlOyxhuKTDEIq>Il_(jAr`DjD7#Vq>#oYN_5|sOGd-AKs`Qt8TB>AGSWlkEv!D(n>66^vT~Zuf`b`VP7=30L@oagDg6dGTsX6kHrTk^v5$KStSs~CnYTo z8N!khFk#wB4e`dtBH0GaSvn&5cNZruLx=32i|(pU3Wu_oKUdwIpLh<7GCo${wVb>j z{>=DTeiwDpF*L4;qA97-qn)R@q4i2zL-Q9iTZwfUv6iz^uRFneO<4j8f;NIF=7XZf z2547UFTpTVX0eW8RRwf342Mai^s3oZzjrLmm>FC9PS?4hTc1Ra#4tr8MK{G*S4&ra zr>wO$7EEr$-|S*wp`WieZ^++tQa>cfe9KIvC8F2VdNMym#AICRTX?cQ6q&H9woveC;^BICXUmb={vcFN$qSnyNP!QaO3n?KVhr3koguM$1wkQor&<&9Z>K>o>oq z&e^UMUpHEsjW+Ns+Ih^87xC-4mRMHuR`Ry;R`AyG7S|aO#lX_zP zYSv*b^U_-9`Zx8`iwV39aOpJry(*=e(duP0pU#U)Kr!I!sF}}v{mMl<;0quQPzneJ zfZ@^bMnI=WCYDL=FG=1nqh<>8q_bT{-Mls0Rk^>a_D9RQJ*wh&iJ!c9+W39#F8 zJ0NsmdLP%4me$V-rQFKg%-k}9uB@%Bi@@5U^-iMBK8?srst55j(=j`5OAk_~Cnr~y zXXd7sC;1i%4JM)LsnXZ+*|{yvE%axyfN!(;XUg_=N%ZbEb#+*ySi&3P?lPCJfR3f* zUn|8cUm8d>K$hu9056pQ@VJ{ij~dBmM3Tai$dWXY_>$ZxIB$}>QQwhG*o)OTzw`(Z zKt~ITlfkD&7edLz^5R{a_qRfR5-dkLYgL_Q0sTl(&nPj4W-$UDs-%C1ZM;&LJwldKZ5GH?;KXSd#n6aKierT;FXTSAi@1blU3|nk6#UcBIDri z(PBchQnC@K&AL1_DepH>4X z`6iIjfNKbW$mrM)-6b9fy`e^Ylb8$~8J%uOQy7X*V$9j{wlEFGSJeV8Z!_H8P4g3% z;7RuEYQ^+0tlSHvBU;$|AYo`-go)*D^46eI4Tt&M+FV!!EVH#YxeU}P?%z7UYNgD2 zzjli1yW(H}?guLt$1H*w7V#izZ5g5#>8E^LEmD(w+%J%jak67?8WG2ytw?J%{C2x; zPbD!&Bp|+YBSv59r?S79iBbA2r59TGz{MaB-t3IgPCHa1?xWOzxfiXLYdpwc60d)Q zgpRz{jyu-_`jMm1C~<@+z5WFt9igmYbmIFnAgCZ@B2XcUA^D>qU?AWj&?3kpM1Ml6 z3b|#0ii9_g&$|5eWaD=~Q^lD?m_(m^8Uwpa0s$u`OKQUk_gYudkMM7j?8v^e2JzqJ z1i2HMWJu{);m+#*8_EBUaxz28%?fuw7sZ7zAYF>;A0?c_GMG~^VxAKZ9mev3Km6ku zb$rb~$+G2O|2~>OpgqOWu77an7pL1u8kgKQWS1x*%0wFCp!BujC7bWxmV zpHcl`P>5a{Shr%LhwPXAVOXdI!w1Hwt831!-Gw7&ei9=Ig(Hm5{-lQr>EoE8AF=#p zp1QN&$ChW?RIk53Q6OD=q`6N!tBKzf;QsoZ}!gpPP^g0tLn5mz{ z@mZ_`|1JE>9(4a>XaDz-z#k3!Qx_r&pZ_zo$~6Q+^3FhH9VY~4ba|CU^WrvFB)r=( z47i@kZJu(IM5?^QO)Yke$iBVZ;m!f|^ZSs}a+(&5(_GBKmoq%YGP^TC_UV$sMNF4M zHF;q(a|`$bp48$J#cv~O#jFUg4m|10>5%;_If zS*{^o-S_Xj5I=i~I|{@&r%!m;iroQnd>j~P^uIf4$&-VS{|ZgAI{!@0V=D*PO6k*! zlgs&TDv3aWg@WrzabEI)Z^-jbRAkuZKLhOf_DT5!C&Y!xi-M8QoqkYaPyY-6@_ocX z+x;!}KR}=7*e`kl0{A#yqM<@N#mI?6kdd7~QT+p~>|gsci7Ajqij8Xkt?C-}?L5aRbj_rf_RD6^0u74=hUk(ck0qKvDRdn%G ztE(-o!Vg!4J!qOn0crN|pYkcphvsQ+hZkjtUUO)&8ijT9;-L2ey_jOF~R z#px+g(P8KH1jO@2;0{r?$-;`-UWsI#6di)p5whe1R?OYtfr4T_HH(qp6Z*hznfka znf)WN%sK|2zYjkrGrvdG?GPVxj6NmXxI^Xt9L(QgG3J5uH;D24Z}9$+w#OB-;9Ww-gC*bnwz6pRRMf#4ncEGPz&&b)-xuW$ z@ubxs!>jB`tJTAf^RR~f6Mc_s)|R_OL%(6R4jAy?BnwGKpXIOE#+6Xy%IhTl>pAch zkumF*_P$^K7?|%aYzo|XCofC|vYWR&MZQ|JI~^~?3Ya-K3Vpgsqv&CiR(+A)|A8xL z-SemXwfyT|xb~VTd{mT)_p#)d0)0M11d-O>WB=FwFL6ANq*WUB2r8s@iWeqm62CyG zpjVd+JuY4d*7I0_jhkA2?#Uw~g#i#CjAaSzb}8IXu%Tn zAp75Cpvla4sd_lYQ;=Kyqr{o-l5pqKEcsciM!|I>kaqa}E63CD?=cIugH&a z(j|{!d13j5kmADM?no zBoCsxugFe26eF6We}hu}=TKVd*LV=Y z7+y-9c1T9}NB<7}_kP4*U5o$8nGpKBGcoQaqF=KkDcMN1`$my@l(&`JFbo|VX*H$A zj5_`0)zY`|(Pd8D(U&4-mT{@@O4DEh*VnQr5%VS^*k&HYH9wP^aAmh<%mqFMHrRPYi4n*qbsCE z==g`{t79cJOA_VYSMwj{)bf4ake0_VD{~Oqj?RCUSDbn||-wW+%%~r@DGPv~EiHEYH@8^tH zBPovdIz{J~{^KJ)O3MD9>t0^uhX|SYUPq#o5B)zMy%>(xzO~|eDX;MdY@tvZ#Csx* zV+b)ErFXg_jXx72Ix^^VMf`6Bn9}RKvlPup_-Hpk8>bbxHiP^hDEj-6tc+J4jSvKv zatA%iEl5V7n}*_d%wMtZmvQlW8e&>Mx2*rNQ0Y5tI{ z>}%Bjv6FvV@Bcggo5yW+@XQ`5SpmTn;}aX=2%Ucu3P%#cCSIq(6D&H{wehzOvJSNV zw)SR33-doO(I}6gjj_grXh7#*isF=j;DOhvjPy$mK@j5;1L8ide+Eir+&{s9^EW?m z{)@bSyTZS~*BEOwh`zM`Q7A_-2qJi$Vo1cY2*?(M?jWYq_`9MweMcC>{a-+Pl;}u=YFsg1qycG!d2}i= zL~|Pde}(_6gZ@v4BK8&uT?!!^o$3{05VikDl$T)$A8`L$_~RwwD{B7_C{Do$2QND* z0;2>`lKY&)s5)yArZ!3N_3a>-xV-3ufnO>mrp5WF(qFQL07Fniq(kUKEYV*_e|r9B zJ8c{lh3uuhSY=l-)@qeCUO0W#mA{k{A;4sk@W~wWhu2qHV?LS6!E9V|(k{dRWF#~c zY^A@n*uU6d7w{)q30E8&Ver3d75EF{eMoQzJ~wDLaF$cIv;XmrBt-3j6OOYT*0;BJli>M=p8y z7jsqe)IhgZKwg0S*;c3Zzi^X~!X%vtl>P+>TK=0U15@(mciz_hxqLi-~|GT$Lf8GU#=lQo4*L(XTEHdAp zsH>HKmB^x1mdCla)cg30z?<57Y}GiJWpVC!IvG?P->11(4i4JPD6jWavw9kyV|MxL ztw6|4Ca__7 zcNIgo?^Y)Yk4b$R$D&d)oPNXu-?9axW;tlyq1*obpV-eV@};F~8i$=yGEcgAHQyI= zXVgLHi`ZTg+Hh`JLaS(&F)H2vhYap&J}Y~t)N=Z6)UFRs|N1=Sx5U~T6!l+!J^}mt zqp-gVmWV3eY8Jt5QYs9G^3rB4H`)4vgU~79J1KZgVttY>;G9jLj#am2W2AazVU`Xr zKXVCtZUFf7!%`0gW!7if%w}icS5$gj>eRIx*`=}AQIP5`LB9euwPh(NW-kuLLIH-U z)A|4aRRg^dxK3s_0Z6Z4>Mki6&ZH})GIf(g%mmSpbM_JyI?(W}AJ0%%d_HfT@r=kv)_J zrdlyP=JGh84Wn%vzTiTEYF$lQ5dP?8Wm|4qeQ<3PxUjrbI}r#RfWInNfoD!z@hYYY z#6(Dg-Q}ZZ=VVAf^+gQ=C>}4r#dh6hF}h9Kl!AE_#ulhN;%2{R&Mq>zU+4wLRKZhz zElXHo)Nnqp;T#erBYLS{vL$Lv zq@qXX{n>bI%=_mt)J=(T3iNa2F5Uw(Dr^}BQ7_3(Lk#5DZnjJ^sfq6Kt;VDGyj_;1 zE9f?M>9ld04yfl$U4&&TiZ_6P22pW#&zcw>C?-S8`7sL zahxN*E+D0f!-2Y#>Br0gR!I?s4V;Yy@e23`*-hcRAN5?^1~A0HXW*Q>xFKnvaPXYj z=J1OmYmNT^PBQVg@4r9fIMNHi`>AstMh>X4&Tfvx-2VY5}~Y)x#8c7e8ccbO}6>*`E#T}+<5moI$@0impigE={CFacvLpKnfAm!>ohzBmuHxo{e_enN@@K3iqBFom<_~;vhMy}9 zOL$G99vb^)S1qxQa#aN#8Tb0%=@^62{Y==&`UqaO_)67OoB?MN+#j}i3~ z_7n6I5k2+HCRAt-yoQv_*TwC!xJ!LsqzI=VBhTU&@g#R6cOmzY|X6 zqR?jR5DL@6UvwVf_`Ui)lvUdM_zaO^@ zP>ka|FZnwKAy(`VtDYL@D)fh!@|}zjJCIKLc{EZ!6{F7cm=F0JgVbLYaMki&(Mc(A zs+GNB=vBZ_%ZaC@Q(#mpiKow3AWtx4mJro5(F zod(T}Ja1?M-yqwJ9QGh%Qy$PJ#4X0H$}QBb*e%7aX_|^hUP-N{M>GF447H?bR;74{?2eM88(HEk7NwX1`Ki1eNIB%i4)2bKO~E^bW{FhR(U^ny zgV=+_gP4PagSbukd&oURXa{je+@`%&Oz*8QEo&@gBB4T*tU{hlet%wnem;b22V+Oh zrs*vHthV+8P+E_%JT@~SGcGep2x4m!S*ryU2dV<)fVz4NZPaZ{ZS-wyZEwnxR^nG; zR}xoZRuWd?R+2=bMdC$bMG{3~L=t#qv*exv@@2{L+4I49N{~5-=`K}OAi1#2fw~IgdTeQJ0mk@HM;6XxugYVH#p}YKg z-($>ReEder(fBZ0eqH4lb=W(8!?9>?7z@AtSd6PhX*$E!@H3Ze16rbCI+tPt`lMk3 zmwW>{?O`65a{D;llsLFc#(s20^;4xDJU}!^G@LY$G?X-$G>qkvyF~kbxRqr<0>->y za*}YOdE#_!>m4Md)-K(yMM)QxsBhk|#AM7671KYozVXy+>joJtZR7Z4)Fn+w+#yLy zH`YQoMpHM=eLh-nL%B)eAdz9HVL;dgyu_dq%P_3IQGD{wyV|NZd z==Z@-&4^8uPLvfKofV@!RJvgW+uGQ&h-%d{q5&ruM;pf*#~LTj4T1;2L*PO1u;aiU z>^-buqXFi*;R(CkxP;+s;J~6bqF^c;Dln`QtCOu0q7&(Bg==Q-xVySm-3RFhtq0{5 zYR80z!PQ~WfyJlD=d2Bi6J_tDyP8)02dNdB!-UTXmxH%3emU6 z(NTl_Fi{x(iQIMkU6QXJW%T%f6|4g$ew}_73R&)C&1t6++c^6W$C-4fPJu4doA648i2TK#JZmjy?yY z4}F9^w@7x$cS+zfXwoCej?k!3tFAe8sdWiVW==^7`;WSOAVwz z@#6x4YRoHL)mNI6uM9ckvGdh;)S44QhgjvKAf;!Faq)vguPjQqlu{~|N=809s5@v| zGS$Qj#?KFt!<1ocFb5bV%m^l8Q2_xjfk)ISKT>LJGGoSn9g-NLhM8DYorF|NdTV$q zdK>7Lu&8H#%+yF^R$)|OW{$UtPZ(l?>B9J7-o3eHTC;EMo<4mbN=S-NN^l=y9x5HO z8`>Kp8v??VV5~3zi~?o|6NZ6c$S?^Q4a^LN4^y}Ja*}e=bn>-Y^;+#(em>8)++M3) zwOzAaz5cC!0$}KJ2xrIxCIe%z2(DJ2&%Z0%*YZ=nc@A ztNL>WokuNFEq8{PM=Mf&eFlX`RY@&w<`s{olKRxl3m)}RwVD}n9__jkZ`*dgAA}`R zwpDsLi6s`cO?uf{C7QN%dbzVDya}58GZnMN*fYh=(?ItSU<|Md7z!)~rU083e(;tk z+13n|1`24jeV`~XDmKc;)&^_I6w%DsP20_=?poJLxtEsjy6+OZmkB7h8MTSGskX^c zfLF@ui}9yDG&SfnwFopdc{H`L>LlPAEz=I}Il%CR+=~*>Q?CNm0#X?z%Ibxs4JF*u zi_?oUDZ4D^*zWZLGHvQ@3T^srGHu#zDjB60rI)3r(`eIZGuOLF?%6ld&9WdJ!!nT^ zHr3afuhm~`CzT9OGfXqgz;@Mlr*@y8lep(M%Y(E)${?fjqS6_jUA^;X=Thf%=N9f6 zH(@s=H>o$xH{Y6#Kb=}@_JM|Hv1n<_jPbPauF<)+dseft@Q;TA zN)4Ri;F;AKnqAd%obzO$!M(b0cBY0(@#o^g8N~Alpw_)Ug~oXCW6_o-xX&8#=?vvP zvwNdgL|C9(>%{sYd^)GrnpHY{23qUIDy}dcTWiiLr7#1jbz_wnp02L7XO$VADbveL z1QS?))r-+8OR&z@OVO&(v`)}V&?=v?u1i%i<58}$b5E6UwPh%hU1=Tef-IaAt_O(c)w7#i(ku1I;FTsTjhw2O zbC__Lc7XKRy|)7_pp+Zp^Mu-q5h%^PQ<{5G&3-uDTjfl0_C<8P ztdEX|7tI&n>WzHVeH483ePn#JeN=pmZ^dpu-pbzU+)CbREdBr$fGR-Q zfa&(>b_lPHv0Yl7W36M|VJ+)|79j1S?cz(l;jQYe++sF-+QUZFuBFbnR(Qb(t_{el zHx~SHUqCU9Z4+F#T1T^>3deybdl=lR3ub3bE8BdwDXc?;M|f!6>XS{6**scr@qovk z#!~x1nTNLb23SN{pnv8h{2^*O_sm*YI%;P9%u85YWjgN6Tv$qFX6npMSYmv-=FDDL zW_+d`n3)MC+WrcRF)B;i&IhI#RcLP~027SL=eFybm8{&A8}{6rB|LZ8+KgW380Q(6 z8Rr<67#A2X#uR z{kk-23OwgH@pN%R`uE=N0d7#*42j(3lH8@V-IeCtB@QP9&)M4avx-)8F1Oo&St4>- zWh#?}yHjU7H{~}k?s@M$Km{TS9THjPO&^`Ir};IOzCFs#`2!*UjJSY6yC16TJRbC_``AT^Ymwk=eFRv;m!Ds!#xow zs$Kh0bG7hr4rjY#2kl(q#^m1fKEzMsQ9`uf_1xpM$~MEf`i=384MxJJDTMI z4z5TRn#BQ57p&44s|~Ve(%Gu!ugK`6i&ZV-$q1zLRV_5gc%;isxOKj8?@MR==1BiG zT=f1MF%bz7SrTy)X%a~i8J2YJr1?9t);Giwk<1Y$eF=SM~H9MDb{%jm=Tu!zb;X2^3By)`rjBJT$iS&u^iM)+ylJ0Qs z;2ihr^qNR^WZ@tr#UTlg2#)OSqv^w2S6$~^cQz}o8u9A(g6KF1SqK5jI5Ii4NJ}HE zBDW&8u%fCKbj-?lj5v(m8F3l$&XRzM!K7dkFqtFqUgZ18hKPnp&j`=R%ZSTJoCuuA zsEDXYl?atctUjy0tv;eY>2-y5X0y2Cx~loBzN^`*v0tY4JoO~2WTM22k*_1OA}IQl z&9tos*DN?UvRvnD$y*&iEzhULzQ!DOrnrYzp)cQ5%k>Qylk>jT{Jys(^Y#gwUEID;vn}6va76lj?@KuK8PG9zo6>SF z?xKC*T?BiBM5?ssC*BghrVFo+MkLKcK7-oXt$00*Zmphi?VK4#TAjN<_|=l+PBJfT zoNL#tad&hTf`25~mip?U+hDBcfh>q2qd?D6{!io40d5ICo6(+`?v_n`d&0lpn5|Kn ztqJcs+)tc1Z_^kZ`n@L^3jyT0cO=Fkz9_uE>%IM6?CwQ^35T=S0!$nl#D`7tUL1SL zl8i`_f2kC1vX9po9Xg)P8@s*pI~6)Se~=?P6)blNdeL}EjL$c-cmLDpo8Jef z%z|FFo152{k%_^p*ql}_loXs?`(18Iy4xc`km4(COuFSy-P_i|jrv5B)nDVg&NTTz z1d?^=&GL`xcDnm5QEn})xe{im#$JH6mW_b9TgNu*BX_9z!`S5|HYygXDwqtNEIG-Z zt)3Gl^Ws*}RwUD7*Xq)`Br=DzDn;oQ6v5k=jzO(Jn{g52HawgMnKRi;JuN%s;+z(a zwO%w6%CvB6!{bSumCL5woRa;LTg08O9*%paOAopLTV^Y8eWCg!$+c9T_*s*Ska9c> ztyQtQ-z@R8?d-8uyv#9o_P~iTE5~LizW7X4v#r3*`Y_-ecp z{AgRa(|Rx8!N2Zfd96(cKQGIaT~J}B_|eNho+bisT@+3k`;Ea>wL!C(YtG0)QhOTU z)>&=Ec{*wx7CXXeNTzj@$4W&@omxl-h7w+_(4fed)*;Jaq&ovjJ43GZI#>k zU3ZLMyOO9`vL5)7(bM&jmMhXN`Z8@yG1vpA{0!`oh`r^Y*Gt}!#U8OS?#87I!F^2m z{@ZzqsC7#*Qu2o8EUxYB{Eg=xDP z*vllq!B^p^SgLN6*b`4uEIgZJK4lDsQ54?(u+;m~bfL4%{7Y}ksqC1At@+s4as2-sgDnO-b@<1 zTs~~WAI7zmvGE3=KyHyqZW=1t?l_|u$eb&_pw#_zcEQJr z4NRQktLphMqg{MMI5UujKiwmqYMp*WSxB049;Zm$OT!JS_C0^4)+}??{f&fNdGh5q za&vz|KLDW(H$`5DnA@XfdZt`=FC!^8>IiXAz^R>;&8jlQ2ph5(M_Z7NvD0yW;yQO8 zcTTXadrz$^<_2`#c`F0d0&^*lZjPtfix&hQ(UF|ZxP^g#D!zE3&Kp1^tTjd##}d30`9I^UVvD{|78v7} zhf~MA7erUl0p1>W3(8sr((2dPcylvGCHYuFe-Q!D7;aiB zQmZ>>iU@Apf0Yciv67GD^xa?#P|g<5Na+;<@DjsZxFvi{C-G@_Lh|ov+%5;WxI~Uu z)-e@7?-Uka>EFA#pkFoVjz9!|*R9lyIAwXHN`G-`CRg@$FtW}z6(j+lW=%cY$zHGf z#`b#=!+h^v<7r?j(irPkTt9rVs+nUGDIFQstJ1Ka>DCH^gyV^KmcQ$c7@D!xPoV7- zEr3YWH|sguQ--OQcIIrmRuq}e*CcOPLK*WHwi!n0BrTc3F@PKMGP5jRDQODaoZIT6V1G*jFFy6>wW=!MwvMARebNo!%!kHqm$v<5?wkZ&#c)zo_3{2~I zCwH&WwA!FDmD(@7dd=giR@`g0lC}0xQ3RDON>d#q1!kl8)yge zl*tQ^=biPpvb=tl5A&THUGHyXaOy`|*n^}Cez()kD*h;9;AB*6OnD{>WB)QFtP;bv z0aTeC=!Oyp=UedF#Y8YG}Rk$PcSzDC$!KP%PU{ zL4f*2U=z6a7k-+0>W=H!vWOZ{<+|0d)JD{LG-b)$!H6wBGtqEmU;WL1pp|}rw>WdGl zYA|8Wso__R`aX| z<>4S0`@GrD6^dT>`Yf|4;UJtQ)RkL%!sPtwEwu5Li4;Gl$U}JMW`sOoM3{u+(D+Q! z6l`@sQEPBGjD2B9m2$tLp6Hz|a>COuY(ZEvB2;iJwa9WQo0X`vBNQ|{X!7CKCf)&V zEY(0u`Pmk;-mklmE=@cOXxX}TUR;~bmvF!~tC+*x1P)GgbCPpWvTXT!a5+jR@P+r> zMnTljV(uDS%>&?idlGAGy$I4{=B-)*)g;SV9=scT&wi^^u)KLdwb(5j@iks>XFr3- zEF-1y&?zc6)aQEl*@o*OmGJE+Bw6newroDVs1b+@CP8V^E#G$s$2MfQyy{T{j0GOr zvdJiyQJ&24piiK%!SzgAqU{wE|k z=HTQA9g70+bVixmmzu>T_@wZugSn;MHpT}`cu$TU>zCQCxYou>;9{oH^A4f`K6{qE!1y3eg zSz{mx;E2-h<+y$>0-)aY2pK@7P7frXI0s-@BcKY^EqO zgnPggK19N@-O{8|C%2AU_bi%=?2M$-O1u=y6KwMWv>`d=OEvw&5i~wOT;JR)bcnjr zU??$+3uW#Lo(yK!P<)tEq8}}!-ic9R0uhEr_(mS)(Zy6e>o$tIB_HI--S!w= zy3t><^WEYnY{nhVvlC2iKX?44bs_3H9>&kSIWe)uIVDPps&A#EC~o>}&|xHg#b>(4 zk~6e`RnSHbi4On6)?)~T#G9<} zLf3;+-l|a^StYL+3#%-N56{{BVl5214!82|=v^wkOk=>tNezz2xgK8KMv5|6ZrP!C22gF@g%jD7x#12l0&r?f1vkABH$|kD;lmpIkX~CEJm&9CeMN?BkQrsuZ zFWw9E`Pi7)#>=z{3S~a*DSZ}IF~w9u+%bxjb|(F}^AKLKr$zG$wyKMNXO7sTi0j(W`HFpg%rx4SjY z+v?8L-0b_D(y^p{pqn>wy)uY$dHX$c$1mnZcU`hhj^W{yZ}4YU%ZpqcQ*11Q4{5jD z8SgOR7k+VZBP?X$X09kc-Wf6V^Ue6ENMz=>R2v>MlW*YKrT6ST27K*|0+KC9GW_){HFx>m z2r7_Y$`KNx-&aA{aNRcI;3Gv8;T=9jZ|-l(jLWv17-y0_g(>~itSTlF&&Gw7i2RGO zQt`#KpTQfyj$lA_DdB}Ay)L-pLL#Gzo?JVN=BL}SiOf4qMBcFyw?s;I_oXRir1GnT zDT@~ITBj%^W~P+Tifa|tUbhMW>oEOPF2mu<;5$1&wrb8-`Yp0i3Hp+!KL0FJm3_aw zm{hL0n_WWuNH`zyXj*0Yf|q?o$*p-*_LS8SNyerZ;HLXAkVbq{V095hgf09zm(4YO zvxSyDXKQA&D=b9oH;2yJi9 z=EhLYITRAp4C(3c8z-?>QWlhHay`ggrj;6ZAE)+jnWGg`!eo(}r?jk{C#LcO4LUdYa9jumv<oLIAbuad#KQBw)5dJrILyz{+*i`Jtb!N z-R~VF@0dCre#^Yn=@$_hXFqk|ooo-$M*(MtcW%RH$V69Czi*D-R~^Z9uq=hQy6axm zOy^fQRrU~Ft_5?xX+ctdGno_h)|A;lr$>ASRWkHMCrtoHS@%O!yHg;_G(-BZxe%%p zJJl|t!CM^eFE3T{%~;mgme&ymA#+5ROO%+#(TDfW7s*kFWyDdjKbIve6!(dTsIi6n ztjAw}B~f^*^`=ILQ?H*fRbS2^nxhVUF`Mev%4IUVUNl!rZiX~oerrv|ZDAS4-KEoq zzJ-5+XI11tsfnc#m>nEyLeJA}<$=%Oe6hT~>ge1}*@sbm#HSSz^Gq{^SOj=wT`EX9 zH_`JcL{=WVOa9Ug*0Q7Cn@v;0S??9<*rjbGq=$Xo1fzoNdKX;3&>DYET<^g3vh9@w zcM!}9_YC`6<=P7ct-cp1qHPQZyn{}}nwK>~j=R;x!#af@8N~QVF+%j&@gS*oef*-` zeUdIb8fema{7lW-OJ^Cq`QRA?Jmsj!Ce-5O)=R;WULQqHr>4um@@R7;Bg<)o(;CjS zla>KBFI*xahRk^O#-UTbM4Pa!GgFjzvVkR{EF%Ki{i->wu|)_%g9$6=E@_G(9QYKR z7)gAr1|fq)v|`l0Sgi2OaJLq;@l>}2X~vTSoTAeV)lm<&o~U3Y4*>zzT95toEYNBm z_O!hgsFmTJC{gi5UX6)uJ9Q824CFNb6u$)SL()6lJ_ zD52vaKa&-`(~02})3q?7XX9wZ%;qruB#d z(j&(SzLVwVAs$SpWm-i!jI9i+{HWHlwR~p%x%c8o_;EpTN+hQp{B@P!{GspB<_4}| z_Skj=m+%uX609tJ6mJxs`qd$xAT*WnI($Wf_+{Hfef_(c7vW|_t>i0xNk8i!vPV+p z{k)jmr8my<>yTS+O}0{VQvCXgS$7YNQ8}0KsQr*;e>;mBM9(vCy_16rcd83q?|2s* zo-|pe7$%wJe}#8zn>{w6!dxPC%?UhAkhZ)#D(5>mZV~gas%=AbD*LvTB;bZ>@`V7X zQpo)pBJO6~RA7l0xnxNJhI5V~!U$nMMtK6GBy-F!-nZ9t$_ zS5t(|Y^B!a<@s9kO-1aq#2kd9Q!Ved2z*SbC z!}*cLCZt^9J*Q>8qK*XDr^ysQYdK<8hXX;hNKOm1p08NRswP9zH40Kvbm}`hkh#xe zH^fa^k$R_lh91zB`YvVASz~-XtS+X+O>Z(NxgJR7P&}gVJI!=Osc$GoVrEK?57N*F zAKECpSScu1l3mPxBjXMFMaAs*vY2vKVH?f+$J}`8oQiKD1tH|ff^SvqG)n3CL#>iz z%ybS|-uPEWPuzUymHSwp$zj!YN+qP}nR>$nvwr%J3savqu=jqMW6ZVIH+JmVV#=P9 z+Ym~hiEQgOTm(}72#4ePHG@wq^L2g+hXawazmR?66I}yr2kFDw&EiotT4^-vA;_F7CD!!3A_woL|4)gZWp2eCN z)U=4Yr1kY+FQaZ&gZ)hm#!O^$1v@H^m|Vt9BzLgRk#N#LxX1PBEIIe7xqR@gxVu9C zd3`7ZNYL<)I2;Wlr@<53 zI)(^(fju@zk57%_f%C}Y(g-cEVa<^{kZqAJ@Ba9aASE~D)YgsxXH3gn-6hORQ1duH zMzbQTlQ#(=*F+;&l?uhMIC9g*^7(vLye^FE1VUyy&TV4(N1y-gAZapaij2R}7;l@C zJozs(Q?O40JQ338NhFs6R2&kw6j75)7RzqKF7k$C#HC9HWxDD)7R^FUtAjNs1$BPm zy&cHXHl0EKAhjeGFRDe=heD2aT&7--`@?#M5|^F06uNo3X!!m{^;t z1zt3`;6M`5?}M3mhv<+Zldv*I*_K`UDm$%ajKSC5=(Y#yx(8ahkJQ9{mduSBU1c<( z6@_@ulh@|tW+6N-8qZL+B1RNXqnVX(hg8X!QccIYMf=JxodiG;7t+u&+hLV}s(ER7 zXr7WL>ffyx)Tbh-*_at9qnRdT_sv(G6BN#RUnSj21kX%^?2 zDsCEZkXF^O4;TNN;%b*trl0G+TezT}sM`?Xlae%blU{Yo=l5v{nuQ~fL=wb0Z>(S_^v@>RY; z)xI=*96B>hjr9biqh08qWAlmyHd|7HE@|rOxCxqwx);XN|ZsQo?mAP|j(_!%!#Xb4>UJ2;= zp8&Zs9jxe5e)d6REsW?QJVr)dG``9h!bA#C?u)V(s2S#(;3wac;bnC5<#4Y(7UHO6 zC6S;ik-pt5lqhWjU~N(vx!8~5h#(JY+BbI1eFBI06zawq^T0JKP$d-<>L`(WTnvZ= zhIPu#Z?eSECc^NxYE}ftcs{saR4S57f}n$W$Ar!fh`#0=k|kv;1d~g_%=)GDJu1c@Sub%^C>=o0O)p}> zGN$tRC*Zgp9>n&)Rrp!q%|xY<=BUXoRmli4%mb3=8GATz`He8y)>o;LAkaD88=`!I zhxq93M|Ad_qqfdf@UE3lF@@i+2u`mgAK4CECmw`XX|caBlw*v1?c~6>VsDS$$C|LP z>$&KbjN0hTv9?sS<$kprsq9)7*Fr8f*zZ%nt@6ut*iSze+szMwPBC#wL&H(lCjQst7b3N!p?N7r82RgfY6vINqmH?Iw+ zg?NSt!a!Le;%HFtdQ#*K!qXUGz+dUb1ml!3c_XQcI?3!JQ?76Y-Il8X@gsV{xzhy1 z+a@`7Hn1Z?7jX?{qSOrHXO%KxOn6+j0$Y>MgT?Uf2(xhnTK6Mqi)1yt6K5fh`62|H zR=5cw)X7K0#-3}<;Jh>z8u0*SeSdSebrth6!fv~lWc;b4n1c@4esD+ zO<=ZlF;DWq{n)tc*AS~p2h)d*Sw~noS8iKS=su2s&I4Lj&}H>5{N(W}V0lx{69sAD zOk79>d9$Si_Km?-HT$VZ0+YOhI2LdBZxopYp{@~jNMij%`NOP2+St9BmR$pX7B@t& zN%)F#sYYQ+cQ7ZRb`RO^LGpl#jGAqtJ0ole*LAE=)jAWvafq-Zy85>$00lKa+pKsT zkD2wC0&Q-^$}y|soSkC&p2Ud*qQJtuOl5moGgIYL4h-7#@XMOj@K<9T4^1#XXNab2 zmN(j;f3p~$La*&3*Qh+PqorF3;?{A+i-8%0xok4|Wm!d6ew(JLpm!;bMC#*358gSO zQk~Oy#&5=Y1*C|YoF)$>@A(I3helqa%|=cdQaBh@y_}d$0qfDX!oFgiHWJ=U2P+%51W|YqfPI_zbsVzwVXdyQD6{iZ$OH5D z$boPx>Ni~tcX>1UG0vdEUq}H&M;`Q6s#m)3$O6L5XuA!#-$e@4GVI5-%?dWq#rIQ4 z=8mXEsYaI)dw)t$M`$gB1IQ<@|Jn+yfj=#iG1DT(szbgQR#z5Zo`&HDia+alkmh{i zIDxzHT#$f)Ks}OTF|EQ0K27ROg88>+>#U}kebC@ZwGa4C;`?U^I-p!mP&6{7$dHWC zJB-jbly!$wsib4#CW>7NM`&X+PMf|J(qEpU7lVh`=113{=D1b|C>h5_7TalX_lzra z93gJ&y1zfpiPy-hm~m+)#y@yZWEo+`_B*(v@O$j=>V-J-ZvOGPPN@%DNOZ#5QC#5J zi}4;@TYUl_eST)x-rjcy;N7V^9X&khN>rI~Cz8bw0F@#7YFADXU$D{QAnJ**NC~tW z4YE58Hjxs1(Pqf(H`qd@V1ruw&{~-{d7O>iBA92W`%tS}ux%>qDJYHC39JK^O2{-n z7|lE+EWw9@bu8#-`v}~U8VmMEXGv73yWfP3H%*>ZMZCpzB^-X85}t=3X5Zkue9AYa z6s{_8ieOtdD$hJ1b*N5j4p#9mahMg5t3k!CYak6!<&X%S<^?Z%Qtc5c^{sP|8uf64 z0ejHiL9+bIy?_j$QI+Zfx(QCM=-AKu@PoX(3J4SxcbOy}&(q8yGo9Ox;5tVyHpQl! z0i1fV9Q)phaw;Qh-4XCR;4#{KBXq-+=$3vVvK&KX&H`@`u}4lp)i#ygJ+&R|_M~e} zjUgr4VpRweDwD#M<+q1<;-4L7;Afc2|}hteMNArlmJ>4T_|X*;@3}svHgaEFT$RoxBGrb4V<`Cc&rwut zug=~@e9K>U&P;rj-;Lz6=}#_Bg_YJh+!xr+wKA(rwcP% ze)9=EZFlkOlgGT-0DR9se{#gZ?VfSd0Yn=v1PSYJoeqb8=Bnw~#muM}U*+5p>&n0? zgv+@Y8zC?;{Wfvmn@$iDK9U@KPw#v(jJDfRVYMLq$x)W_H_%+6{8(CBUro@FAl20A zDj|fU>A}YIAT8n|w9=bPQ`LYHT()Y#OcAk1Hgi1nGS0KON8;Ux(+LEMm^%*R#F-Rt4 ze0ay2BTCb24?vFu7oI(-F* zO(O!m{WqwnZdJKj^dBNGqT8R1UIUAVQ)RS)Eig=@AJz#cKGM*hL~f7bMXmF!DB!p=$xBESPq)okO&Zuny_cV}+J*{z%gt_C zEoI_zAGnEdo-Oh}4RCk^m}VUl{tk}8KhXT-f$0@09}kw#%``KoXx{AsEFL zXl->=@qPR7MBJdm^|zmZOi7v$CM4xNB=y$0qSVpD^DlJA+F_5r@jg-Y%eSv?PXHcc z+)JVrt@7YHyPa!Pl`~5crTdk_oM;bKj9{6dRY0_EvHd>1C$I+X%ATDOndNix8HKg= zZ(7O`1k7m9ulakY5`zDoy)Q!Ij1`x4jra%?U+J04Y;_r1BVAfp<+899UN~5aJgav~ z1bx+?Ht5<>Kc}*V;FQnmN}z0J`Wws8m2hLXFp&6T6;*aG267&e{(*3=8@)G3e!yRA z!R|*jLQ+q;(KQ=q2;-D*R{a38&~NL~ zHb0Re%w%NQ42)nzB|S$NPBdJj(g}J8^qyw0 zX-Mn~M?rTV(=u&x1K!%YJgZZZl9IRFWFmZaGh5WvRmK>zAyV%=q6{_D4SY;ip0oG; za_WoBNF>e0rvGI?I>fFnc+@^5PxBl}?n7LHJJ^8% zKNAg}zl1YCSqRFEHN{*YiWzTY!)Jx&McTXPdfUgpk8h%hP!3S2GK^hxtp>dAorYFr zn@uWMrnvsf@lJ{dMtf@YH%eyV?_sUNo9CN9fnbB@YD%oAIPkHMNx@XaApw88Sl+4^ ziB|Xh##RNT9VwnC4G%tN^n@ki+dVhMc%1zzD7U+g$2IsmJTHEb?5L@reLvNFPU_*}ahcBbCXe8zQ^U0^7h zcO6Ad4@u?ql$IAXpAZuhAK5zQB5E!!ie7KU;$SYa*Ao-nUMq-$_rS)vW1IybTaL7Y z=}<5IMR~8I(lU3WoC6&m(Xu8R}Xt0Tx;>AsGJ?CpDfuWXDq z23ZS-9I{=>18vPtUFlaPzeT`e4HQv@d@|2RPkW|;JgOcJNC_Z=_NPtnLr3K*Q3uUa zFz?mcs!yQyd#&yA9`yjH;a4rpY+KN;l}LHd;kJyItH#XS&B>Y;=Rq13;eFD?2592J zy^)jWe21^>t4YzViTjgo9B6ZzqT_0{yBgqy>$HjPR1V=!hD*AtW@#h-@Fh|nl>|Q* zXGH_SEA(56&~3qnc!{xmJsb<HOV%;Se8k6LkXryte)PZ9y_6< zL!E!tYXM0dhrBUt9Dkx!pIZ6_zfz7xk$X-vT`*){kB|idX!a+Pg+HIV!7W$NSZVyugS})eH(iQh zC-2dhx@9yU{TBX>Ugm4r3Pd7>fiiQ=vbFcID(vYi} ziZ7b1rqzEO3u#!=h6du+Q2y=*(>ZyDbo`9NBB!}dmhqeg%dBia40 z8k373wOG!k)$$e+DJ0$Ut=vsilt@Ip@mmW6^b)V-LuGPKAT=OyKNQ)Jp3WBI<&~s# zFnkVsj|%oS>lUF{f;&=o0BESbsQf%))}k?omkwU`M68tQpjZ8;l!DcmPV~rY-jk~B z&;zDrd8~bRThU%+EDI;pL66n>nn8BcvEE#^l3HTAkEc!}>u_m2#ih9L8eT)b@)WX1;@_*Flr zmt}09o4tSYZ0{pTUhN<~4{dC@xABJ13US3vSJb6;*D$t5=PYr0v$6U$PESHiDedbV zaCATGAhXGi zIcxPlYG_zew-W_IkS6F>I3+GZ4%GmWnMu#CgL&e9^=tdcOYf8jdYm#Bln?Y_Juf|A z4Du)R1($b0j&P^?B?b;=L9B3QM0I-P~Ymao^i-F*U%l z3S)qPSfX$@Vk>$l=r;cVH@NwcQRiNDF56G_G#Q^fV`heeB_2Hlpl2~_qC`yDF$Al$ zV4iHl^EF0YuxbH0aWYB4X&Jd`j9I*~OOF3?fHq6eXjrtyo2 z7`OEc#n;;w!`205bt1}4=bfFAtA4WkN4@^xDl6QXO(9(HYmJi0qWhgMz+ZJ7I^k#N zdRB4DDx~osSwi2E@i3n?7D(e7v)ZIsow&_;sfdV3cCQ)F*^={kXP@m|duffVksCPc zc}|BNm74qFQ|D&e(0an!Msng8{}B`#Os0GyDD5_Yg8XwZOkpUw1v)5;akRO>!rrFw z1W8s_=MOOQR|wACZr11$EjZa2TM(-nrnD|4kVgW<`e2JEovn(X^AY963M^B6Njj=i zCl|G=X@%)Tq4BoT?fi<$kYvson4$CxL+LS%As@>%1WI2&HKJqdUIRoh9}&jpX%ngy z1J!O)ZqltI1CaA=EP*SKuwpJ1?U zjy8|50a)Y~u*>?iH1uxC`}5FzVLyC{dEI7leXVDWt}r>$#Xb+n$qnh-s?yATvv~2u z8Px1wtCI4FM8kEOIqpwgB7piHZY{~fJ&ox2m%pX70 zBlg&02BnCsM~inhj4t5Rat)qk^$(N3B4m3W67^d*SA?$bmcIY$-eMX;*6#|2Vmf-K z-en?E+l^R@=^g+FH>W%%axtE4ry1?x8t8mx1o5#w-hT|&N0$lh24J9m+3!aXRN=C?DIDJps2t8kkPhHi<8yE!`+tX^KeFO zSoh?r)-SNM!zi5N5pBA`l;i0yRfI|tJG`%PBY>n8s3ip*B6`-UkGPp_rOA-97g9Qo z7LY2@m32Pn4mli%-M9Ojc$IP#&o0$h&Ik>V&E4`xONiJS(7{TsUC+l7n44tVF=Me4 zGe3vtw*vYvcwKwCUJ4r#4Uxjhx3kmJVpa8PJ*z$c-&-4Sh`@T#qm?KYpZ?MP5FM;ZC97VWSED?G2&b1D}38VcZT(0)YH^uLy)`I} zj7sH5op1|wtd8P7?BzNpm%+z;XLpsbSo?cACJy8_UG z?L(L2PSt4pudmG1>&)roH$KUo^Buht$Al&69kzr+Zn7o%#>Dj5yX=Z?)_2gn)YQ9w z*Ro*EY^h%JJge(g-o=ye{kvp?zE7_eS#LJ-#PxAgQg8Go*o*NhD- zCZzEHseJKr-AQHvzrlEWeqR4~;f1XKpW%f7CN}o}JG=0&8njc=V)NG%J2`-#fQ!VO zB?A+&U+@kn3z-mf1N0BVKtjMsAjD)!&v)kw(9(bo6VC6dfE=Y2=HtT)APT_<2USpQ zMrl^dMZsUz?2h2#%I9@Gy!yt^i0a-@?oe6Q&hh;`ZpJsw?Vk4S;ZEdrci^$lHonGX8!2KuM$qrXjPT69A4$Jy9^y76L7dw!$9Gk_Pq zzGm){s`pW>_iMv9WIIVBr%rUjwe6d-_misf919#Lk&^G)jgLjO6YEG}Lx@bCLKT=> zx%Tg9cg4=FmXGS+$K|DFd=a8^-4Q49QKMfWUrXqmg(GznadS=3rWu00jO&fj*D}Jf zPgf2hFIXk=p#J?#cXFN4=gKGkcn%@Olx1=_46_x4!v1C=kOD&veVijNe3J9=X0wP` zBxqHIW?uGqB6Z2I%S#+Vy&V3{X#2YArR`wz@-9gZk`>U;rJ61o-U9e|zurLg%i5Px zF|33~E-DFf5SaCrn|olr%jg|;Mzok4iXc$Sgm7zH6Ssv1i9yUaGKZANwWMwtO7ZKt z#sgCEP2-fRSsWbCk6iGU4=2?}o#-pn*21k)9`CF`=BebSz0n=X7*x9+VT2Kf3o+a` z&XXcf<2tA3v?fq^y{hQd9Ec>@s(o&(NFA5*C--uf2@xkcB@8WCENcz2$)>Gx9vhC- zyROwp?lS{Ax{Fu2{xl2j-7=&p>*nJjx9-IGI}T&Q!l zOWoX6rScg*@;~7(b?Zwg9*&zQnU1fgvz(JWG%o2bMjG8fs@Xyk-2gZ2AeYmbrr*Bk z0Z0S|HNkkc$<$=)*R-smVCx=vm-ZH#^lNWru)_`1=(QhQ2QFVTYyWZz$u4TPwALY> z`iWAG6fr{Vg!bSzhPI@H$wVBxA{dgnj}N(d{EFR@WUo!E25efc7&305G@m`QhDTm- zbaz2(^0F^bM0TB^*(ov%C;}VIU^XR#nX{?NGO)}LY4ekt{-LjJPt4aOL(79>X3rmh z-Ll6g&~G6%Gro~>vyvZbY(h<92<8Sw802IT28_yWLcurTxnaTvG7n!CBgjGe6(RHJysCaQEZIdxZCSA0#_hL;C<7zDe{G{oz zlqz+WEBC7^3sv>#?bO5CoA(W6_L_z_4p*7<$Wn*#Pv@Ejrq)`UA{M+cubK|6%G`DS z3E0tN@B>jzj&tvvm!QGHSzIYYlXi>YBzKGPvr1FXO;|%tNJFr>f7d>TIt{8gB{GdC znVKbdNdtMET@Fk3GP}2{LrpDFZ^M@AZbf#kP{37Q`BFTbWmkb)qr?4C2W*siIZ9s*rpLKGYUHNr!66hkL zL={EAl}KzE8kchCsMYpPa<=PrkrQ0}hSbECmB_w-CKRu(D6{YM)=911P&{g;c>oV4 zADK9RsWR7~6e4fY|5uR~J%rTQoDWFpH30KnD=F^tX7?NFLD8J1>r#zq5G#34u& z!r{b=kYfVXrhm^M${6xxp>%0(d4H`_7T;ybPUr7-}Te^H2~w{M=uiv zs@vxT$|n4P^}*f`OL zoIy;$bzf%!4-r7|)vu9F59tOw&+nw_kI@YIpU^zn-@SVz5D)D}AH$*vUqtd!56wcq zcX3WYZ+@Q;Vep?Mq~FdO?;!eRZ&yNlFGn*XU9A88qhf~^a>YktFJQ2DErl$J>43qD zsWqF-4^0L%0o8__ui`StV91h(iCTa8#WpX%&6s1z!xqZe*ucJ%1gUJ)Z(8gwMKSf0 zW2{4fO}GIdi!S5bS%6)OJ52T`yGlO(I*^7*30l4D}r5M(ABdde;Sa zmlhfXB?K`$QXvM_NL}kly(xK}=zZL@PS)V59N~KT|{6* zh;~;@_X`HzhzD1ns1q^p_H{MNccivHIJ*Z`mT|-8SdRB^`8plX;j|w7lR<7W0nQ(O zt`XB0gi@%`*FV5r$iO>Ev)utVlxh;OgaU*HMv71c^p5Zj1=cee_as?lb0ky-8rc$} zj#wXQO^leqHx9=5%X7d2g2Fxy41lHU*5U&B9?e8_lHzX^NezA3+ndXsd=z7upOY!BRDtGfv3$0hF?u=2nw z_$}%>Bw^(lsZ@r_-IDW=loL8MNh?v3E9R6s#^nST8IsFGDm@n<(@0Jl55c_d=(=XWEZCw0?&^BH^3%zf$6dCEm)%lPd>H+)uQ;VSff~_ zlEtE0qtvGuPcgRg@$7dqzqL~4LZU_E+8$h|O}af*LABDh3G+F>M|uo%%IVjeI<7m* zHri8cb~H^Um))05sbR`V!2_B6m!W+R8-|xTrtp4A(MBIq6abg z+jO-&R~^OYD)^`x8^`kA*=k);MC;37J!ZH(be<@>ClE$wV)SLr@9KJ`GJAKmxYp~1 z|Gv^T+oqkK#c^$rMzpTx@ok~NZu7gJebX{=K&+`9?QaEL437NUTBm7-Opg2EPS&X` zn^S;vDE-BIIU~UwhE3e;W*F;U6GQ*Qjf^(+1EY%5acXJv#u-Ca3p=!_^0BZ=Q*Oj3W_E-qRg-Azy(PfDCh!7_0>2$xYj$_ej^r#~J6pa?H(WcKQr=faV zj+2Ze?xESb)!^zq`g$w3+*%TjxzN+Or4iNu{o{PA?}x#B3puXkz13->7G@zgCp=v^ z)7x5ssy9aAJdtXPvnhO29Yjn6gv1J1V(+#8l)=S3yb#V}E6d6Uyw%2~ndfF$=bL}` zcKGkq!kS;NgV=~1GQCEeEyr>bv!$ED^27Fctn0ED?mflMnVt$sv*U)=%LXr)13WE7 zHBK%INb9>5dzXboj@PwSRjxEGxPXF7eMws3zb&fIxHjA!omr^3`?sWMlkU?eObta1 z209A{>-LF@RGyFP7n{3P?VT~pw-@bKUGJW33nmPEtErpLC4!vFF0+;RUE3ZPm#!Mn zA#k)*kXsh>*uw#KI)^hFnYQzhfG?c#cb{Twj)8mtxCO>%f{9eM_Go1egTaNz`r_9v zv1E+ThtB-1>y`zb!~_NHB%?ECdCH-rRW56<1KC+oOpXCIyS0ZqvF*jD-Bv9e2g~N#d^U>+ z*ZVJHxP7=x$HUXve@ms!Wkn~*h})+;h1So@w%j{2I=Dlbv2(6iU>AXxU%{|nWk{K` zmsRqntOBypvrlE`LoFVHL3k#dwTXgDD^u8GgdFoG2WQqC%C)eJA!|s{eINE@XMIO} zrC62%HZPXUQ)las@4K{~Pe4}pC+YN~nlzO+E91n07lG!BRb=L4bBB$vj(dF%$=nv` zUElZGg7s$nxB!2K0Q|k}t4A%~(b#lB+G7uNUK6aLaFlN>?%_vq0Lw1(fwW?%7@)D% z*Bde1B;tO6qTx2waN=7O5qkDIcdzzsGLE)HE0+wf zi$7Dh|>>qB00SIOtIkM|AER~h~ zM{T9@qdE8F& zbgoXr#!%uN4el8Fxw1J?r6F^%TPt+#9z)8&LvlMR>OjvsCQx^k6vu5Q1CumIsxmOr zUv)DRpCEIj<)hS*XQIPmHEne6ETUiZB*(g0W#qK!tBo5>+kEkT0_`S7z5S!*GZd%x z1O06x&=_3~DhVVsB)S#0vT{F|k5%rm)~BJ~MrE3#sRTs`1p%BnUsyxa zCErSA6sIbrouG5;dPI%PQ{`MUyoaM@>iT)xi;erJXs6A>U9gTtVE;D(nj6|EI7%Kv z81o;*AdZr)ax4M}yI=9p3m|R0H27)|RS*&1q3gUL=7^f_VCLKKC6*Uh!Shyka+xV` z7N<0u$H=clv@AC^Ul2S$d@EUR#YTk}>ZnQ7e~Sz3HLp`DcnQ(HwV%)nWd3PaQ;LJnLTy*#sTU zEp9Vc+pXKP-=CZd#G;~$vlpajn*czStkE$PpY6OG)BaU0?%O*LHI@KOy<`w6@NNTQ zOTO^r7!;hf=JU9f5?Ut7EF@lJ?z_@JS=|yjsMmo0LCykk=7?718r6kHNIK%K@lmUo zLC|EkArpWatV-mn(SkYDoC0bl3NI-jJO_b1HX0+lw?yk<9;9Kzck}u32~G79`r~1A z(qY@$Vpg>KoD<98wy}0C_MTz4!me{7zZB<-B7wC()_w-L5Ppb5dAnP-K-`DgCJ!j&Ro2NAZ=frQA)pdHyiLj7MH$uxLN9wf)MM;wU<#7t| zgj!!)UypD#HYOpPgJDVtXCjkDe4aDKy*}eeVN`rnr%W?FjcQAjulTO+Bee^}>$E8O zGv1Ue7LP(*Lvrcjv*3DaWuCdBsVcvFtE99bUivzB{nfB7FI>(XQ$XP!j4|)NCq$lS zK@k`teUlQ;%|7{t!U;&LGWlyKt|?rWr8@uI)kaG9YRRB3tzwO7D=V2KxBL#SMMAU7J-6#rIwbjJVvG}EM1&}#5i%^3Pwx*Zqgw5qRR#9J z0h&%k37fro4UW~L$E!|wB$&kmWv~@oQ|uBKB%>SckWsX}S!LVcJyc~68h7`|X@Jsc z_xJ7u-t}=@pRU*zRP7)iIQgIr5W@=m?{vv-GD;$FG*-hB?W@U$uYMi*ie%+-{Lj#B z&cy||xt`Ax`|SSu@U$%z)#^#+ze+>7c92P?3N)tG0p;GDN&Lx;=)VbzRCzuhc1U9H ztfTYgV4rL?TU+~OOx}BtISAjiv(~=aDqM4+A@9h)IY4!x&#l(4esF`FTOp@M{y2#? z;8tDPzS`W;zWR(6-Rqb-9J%g#9kxCf^Zaz_DI0uJ#K)wl6c6F66dA_7?yC`m_5)F0frB;rC3>^NUh_5A5 z9JtqTf1j&3t@B``I>Py2xOGi!QT{n*((~vu@`cLc9Y&hZ78=%cC$=DK&Zt(6yd_W? z;2hI?(X6L!khrSa*TGeV*FPN3qqfW#jD)~@j;N`L@U3Nqsv|3{C&f3I6*M=M5U(It z*$)Ff(Vs=O1X*P$Bc#fj8L;(hGVoQgSydf3;a90|Sf#uryF3TsJ=dMZB#fYvOT(fb z1^;9-Uk92qyirz0kl=o+-%wx|h-1Z{^L{SqgY*35{Alj+MkPaeOfi;_#!Tz5z zLebg4$=%MFfL_+l*hcB!-T$N|7=iy)OLVJv$|)&hd}lYp(}5Q3%t>x)7AA>|3Mx^+ z{z9jMbwETB(mq65xYE{24UNu7FSbKsxsRWHz#FeR$$uSH$PAJ2&@^OEmX@BEntynr z+dO;P?Br7eNPo_^JNDdrZ?kWodmVcnrz9mO6X03u3Htbt5c4|ig(B#+D(0TwCjF&b zf0d#pp#8znP-a&Wx;fE;v?=f~h;$uP6>>0;{bPc_<95!k*1yvoL~ot%A%J5@HF4%` z06pkgE>}r3D$NB?@?4yEc;Qz+?EtqI=IOd%*AOceVRGne;h#9Sj9kQ&3op7a4dHEc9{@K8VEoiXkQRGzt&s9G(XPC z*)o${qD1?>;h`1wk?sTQw$L$lw+~J8lDZ29+$^mm!f(^?>4YRH6Q#dAu3A&kN~qkP%rs;X!;E) z!7y(PaX>#)_OPBNRy$Qc6ddT@OiJH1SN}{g(l2g(%(($+xho5>cX8@8sF% z);But;eucj5ms;%W13(VS;4!zJof2=Bg3o);rE1EwV>W1RvnXBvpdNJBA@K7oqU&+rl9r;4346^y|$y zI$}&VGD^URIkL@Ns6|+0#Wv=+gLdo5rOUgs<_Yf#maVB|@JY8vYEC0`U@Q%AnDD2X zNZb11eK8N~CfKG*wHBUocQ}s2BxX*jw~MFjXe|9SogMj*@mF66s!uVH#?;uzs5qTr zJ%Al8%b-sS*~DbD#J7P}4cq1^7-bdNO3BhoUm*oAn_${_-no7H`OA(%pe4tjT^?dk zW>}(vb}UVlaeiv$w1n++N<3@`VNjk{Di2q-XdQ?nE>=R*cG8j^=xC2OHS!B1Tpk0K zwMK}iL=gxrC)Rn!k9c@Sr4?<-0NrR$d)SJyJp22$AnHyj2C4$@{+1-CVEv6br?1fs z&a)nV+K?Bn?zJjGxxTb5al|gXVgvziWZxYWe;oOhL1(P;1ytuR{yOVJZiWvN6Up4} z+z51UPDM0&j6}CF!XtbFcQ^VoxEA_n$I@&9yRUgj8WkE3T}+rZ_O(r~=o@82N>b5R z1;^56-52;Qh12Qz=~{9BpKMd8-!|`TR(W<+CVE;L_5K6+Lm5P->5|b!LU3&lQt_{Bs@o!6XnIw*LI)wwR!qtz93NXkSDgim3C+MXUQlD1Z^7h7{nYxUAZ@Rh{-3e4(e$R1!FG~*Ar zF*owt1HuAKQF9ko17_#$0}M58zSa6lQM%RS-O2BT@6z@MyI`V4YhnrKC&-Z|XX5kD zQdG6u-#IBa{=>ZXiVNW;3(xd3opj5g-avKit0kmC*O6Frpg8`el?qyL#UM_;Q@G(C zU43)6;vCFz%%|p4L@B9s#z#Gm!Gmr>JGS3-B6Yf#al+3`Q-adV26*O`E8{SA19B|OuI0y8rLnEt1>#ROyp{NEP1S`}6)$r#P&`q>+XDkBP}jCAY=z%Ooe+V2HBtjsSA zvML`2FnYu5mj{_nSX{a}Pvz{wV!TM|;yh-!a2qEoTa`S!I;WMYyc`uaGtQl@Twc|j z<-U6Si2?a{%I5fD!+q=9bNl^k<9#y~(a;KXecUJ|Cn>4D>!?~2EK1r+@VtpMJTj4_ z^nvzFyDU?+3M#hA(>c~SN~JKTd&;IdLDsUBk<7Ee+C09wB%(cVWzhQsUsp*-cg2m) z64B7+1mCe@#e_EPF4FOR_8AdDF)HLXc07D%F&|IOYFqBvZTw|g&KH#-RkfyZ_(dq! zSPJnTw^8%FLX9rdzh|}VU0LlC_#Ju-ZU}-tv!tS|-l$&}U)}d18|Fi{M3x@A{Xwv& zv^D6yU3Y4j_LAM3<)V0yyWs0rzoB}%#B6XOSNh^Vy*cI0XxmywMC$TPFKIodPbh_T z)OIW?(Yi3UQTIgA+Fi!Ol{As6me2g#!o4jvnI(dR^4XyjosQ1$3b9J1aG%4%rFC8z zy0E8@CzWpK;`=4AOD6A#=W_Z(irrJoJ(GI-1>n{S7R?7I2Q~N!&o$8gn&Z9F9F&2^Dc|mP}L(RdKQ{+LmM+#C2C2d)nBEF zRbS;$8I&L>b+JPzBogreXmtZ0QtBTA0|QlkBd#1{MZSkCPZ3qE12~`q@uGgehdb}` z>&5@e;jM?RLpB5aTtRpUfCVEXm=6B==M3}$NdunncO8iEABDWZV5K~mvY&H)k9@Ro zuYj5LbIE_*6U9oi_S*Tu^n=CB^LWr+!|>P+$Uq?{>g8v5!L~2%He@@ikJX1W)L5#^Rb6`p2TL6GGh00GGXE2K`MLkzv>^? zA1JhW>FV!DikS+U@OW0jXjm9xoaHfR=B9cCyg4Y-5ZQ1%7`Y@y1N})xCp&#ecsSVk(&d(>O(105Poh-jO%)Ojx8@$a=NBShjMoLh z4`MQ&X94K6)}b0tQ&L3`qt7h>M|G&r5Q`ua`No&kb6AOmS!t{l7xTmRLw64#)&ET8 z8Df*czX6z&96FF8^x~!8d#60mEWUo1dzhbTO?-y572onmoP+f|VRuI&HweK?A2(Tv z1Mxn4f|Qm5SA(eWYlyTD?~~3>vn0wTRd@A`@}gc4&%wX=w?O6$0O)1udafkCx+U zhGJDdUh2GBb(&p8<=9Sj4vK!^&hi6^`{Vk0bb>u4<9V%P+(wc`xrHNk1rukYlRNBJBm7*hnCNmO*wn{$(gS6a?ZfGoCK zF4yX2YW^?wzC0evF6@6$iIgI=YDz-3nPFy3Az8|vgsdU!BujP@5^YNMlC6!DHAz{D z6cMQ?TPaK0L@1>azjH5Bb4$zfyl?M6&+qwsJl)IL&$+Mbdws9#oYC2v`{~Z5#YLGB zS$?M|o(`Rfn{$#1-pmr-6Px$tQiQ+<&(bQ(F3YC@jtg{-%`Y50@cF$gr_iY#va3Z- zbG+*o&wQh_h-?&aw1awK`mvHNBR95)McrP^)9SZIM}+O|Mu~{3vA|cs5`#DDE`9dS zdZN;E^YD$Q7MZRhY$lG2Ep=RnbOQ^6KRS9wcoc*sCUZ3S&bYg%Fnsxd?rgzz+6UCu z``J{!mn~bKX7?=UdP(t-`+ltrK`#zF^LqxqYoa&#Wp>prJg?5pw$ z)OoU_tK&K^YiZnyhJZ23IL~{^9f4>M-$K&nIC-6$9a0zcqWiB2%T?_iDlI*Du(Z^@ zjkhuO-BB%pCk1_+XO+gH=HB-o^%d`sx2aDvkv*KQ=Xvc?-)i}V)1&w{EiiaAM{v`; z1NQG{X&WuDCrjPk)g)IL{xNdt`S(pHhy7^Cym=Ag|8{oyr-1R=G3V8 zIP1}SPYqx5PTh5WkMW%eVQxjPJ>r?~W{h=4wdVJ}K3h1$yLadFQw_0;#UC9nyAt`) z!EOv6PN}@3dnDGY>S)T&Pd&l7trt9=SKdi^v8JZwb8S<^tF2p9DVm{=Seobim-HVU zuzKwr6QR%MY99Y^JiA-8EJSo1x8~v7(kPy%<6Zlr8#c@cJ;eWzY7%;=q%^-)pfGaj zj>?0#LhZDl8a52E`>!j0QUOQrkSsYaK~q!u4M_t;uszbPNsm!?5Z;j^nK={l1s(RuaVg-i({!O_QtM(g6* zTjmaV#*ypPukRNVH{r{4c({M;-~dl6?!fi^vsEJ3=bM}mjU6IZa9^Achl*i_fT0YN`151cKbM`#Y*W#$$ zwq0kNe&X>5^FH*i_9()iDr+7Kbafd2SpRtE^CTIE`lJMpIqRn1SwFmg-A1#^RnF3@ zgT@7wo9`MNo$ zFl&m&3A~e|Q0?Q2*GcR%gc9fQ*sXmRUb@}6DcV_OY@pvGn8Yn;JnjCDd(8{l#NWLy zIqzR~EJ(2JEG{jqGNJ9}p$BQxi53H6Nn6YeLkgyQ-Uz%G&qp6_6)*eXs#?8rO3HBD z+@pOYL;NXel_x?Z%E~*l@7Zlk9XmAc;}|x7S((%6IUlRPt{Ywwt&{6MYZ-NrQ+26K z`2+6H8t;?XsuxqPZhJkq=%mDQwTnSw@^1~EP4(vWulrZ7ZB2VY z*tH0EQE@$|l$NCQ1i!g5mwgQC<0X8%4xF!SN+P?&yd2Et3O%B2F5;SC9lLKVb&KwDaT{WUOaV{PfY?p?_)c zaIm+Muo8Q>3~x#$3#D$sWzJ_o;_}k_R*4ME6aLI5#k!5Jz6#g7i3zh_!qn_RIhm})gMIBRuWuwC%s;5)XGtcBB! zr%vb3TQGZN`Qkha+yQ}&tkp?XxUDQV1-dk{aFOIhDJx#38NtROA-J&R*Ko^N(tZ(Plsb`|gGG?ojTnUT3iEIDGxV=pAqdY;Mtjf7R-uOztw>ksECe^}BWP?6KF~ z>$W--J9R#55p}kHFL3yb!uGux>Iqw>u3CNK^!^X?E*2=SJZoaAtK%l!9dqm2+eMKJ zm&{wICK$v0Du%n=O=vS4B`<7?I#we$Lg^QA z7oIA8`{JoKMf;3`vu|!K66)!-Nz>1nBHpT*pAhaOdhz(p9N({8q1h zA9NC$Ujz!q1xm=}=3FI@9ja=6$Y=KW%c9h6PfB(UpFde1{IX?1&e-Vcy)P(WGhVLD zW-EhtzKItKa9Jm7O>B~mw@J&yKi~NEjcuCanZ!qJ&ZQ4$UR|bCqH-d+SEw(Ru+L-e z@}RZr&zV;?uyLfuJ^i#huBLI6lh8ij%eJJqD&DdE0RH3to`|6v>>-@V73+_77aj^$ zk{{o9=6cuA_!9}y#S8lyb0oj&ynnPy*ZuKh4cUFuXReY@r}-`mk9moUFOlEfd?7}_ zxb(v`pZT)m7jjAx=}O0L?uZh8AEGW~m)5b={ZNl={L`v;;RDvC!3*Esm@9ChtS`+cTb9TSsAQPlu}d_`|^?K5u*8w+yr{xpL&n zYRh=;gQbU5mI#W~^~olU?k=IfS(c>4mOe{PLnEMyLMiMBwUV>ieRdIj@9N61<)WGF zL+!(AOCEBC)UV&?GIK``&Bk@h+YV~D z+cjS@I?|n%spLObeMtyWirqobN@3X*>iFrCY7eG;zGwR+;7j4Kn3xmzedp~f?pzSx9oV~bRq}`6xh+0wE}MFv zaEMp?S1n4r=JNjem8ROS%O34}Cfph%$8LYD@!jBdVs90f7UlDx`gjrxs@#n1Yu zh-=?kOmbctC*Bk_gmOEV4Xn0{o^s{6-U=D#X<rVy*&=!{o#F!y_x^E$U^<8Da0%Iq*dqqo-~>z#4LU~ znsqt#T1j2`%!O|#f_MGjX+Mb1yWZYrd5@QaL*sJo>)seyjv&cw|3H>YpZ1k}>3&eA z&>YfQaq#?#es%(cGui$gHS5GDCXLgO9hu8(~!7P-2`Ur*Y2ht}QtTxpp#yl3XL zSp#))hZ0n|IHJUs4r)q;`KpDIy2W$S9gL-`X4YOQ=AQZW@qRXMi{{ z#%y`-rgigE_f45Av(p#YJF*Nmnxw2PWSvu4?Z98KEn=p#At$FA#os?uGruh-PG8@$ zza*$~5r+roE}_?Pv(5_l>hfP2UKh5##58GF_5FG`yqMIhb%Az5A9K#-i^YDqwdPHq zf4jnw4{;*PEvcpZ(>@88TpDDrIUXXvpJVq0Num3CQd194DN&xcNqgt{V;g1XA14fJ zZ&Plk7ghydfnyS4~Y{>O6QZef_oDsx$kRu3u)9 zdR*`2ty>HDF36`vsq@6-X3z6~v6=sQ^A)XGBZ`X4H=Bm-EolDwK=F3W*bA+D_uoq% z%AG0EU-jis2j2F?k*ZI|7E2R`T1%uZJ$hJV6y96BE&EK$!92OkZ8@f|mPx;LzAt#m z;b%XPKWOy^cHyD(hT&L&Y^HeINiXYmTZ70@Znd`BH&F(@US|pV`kCoipDqn1FeX-{9r7K(Mkpgk|L)d~nvR_e7JCLS31iGfs z&Wi~;``wPOx~Ri*@xe&(rtNoH*DPqc*SI>+zj~1m?>=`UrIq&U!b?eS2Mkb-KhRSc&)~A zar?THPwu{`JrmIx`c(RX*#5#Gp4YO^4*7(wlF5`(*2=r8Cm`hWhV7Fh@!8&okplfn zMWWn&tPz=dD@LNY+*=$@ik?Vk$W-fb}BmyrLx?{ zuStGxSamtSGiBzkl^w^Y#_~tT*`E&RII*rrDT<@Ov?IE9)9n+wBelU=bIi4Z*Rcoq z;F7sM3+yqM9CwjQHBOn)nYTFOATCPzZt{TQm#6x*&+ldWW!IjtsB_An=DAskvL^Aa z>`}U)poi~(B}Mxw%ZGBVQ)dG$I?5svv`4A4$G)Cj7%_A3X@k@isidOrgtxQK+*01p z7v7OTHsxxz(<7L2h)mUkj3b}ha)@^uC)|49oE+I~{Irlj& zKQ!gEZ|wAD+o7rbK`aOIMOY>?G)WT;O+1-K`0fmmR?$$^aG`tRrS;rhZ8q6?;_c}! zw(fQwu3qjocKEG!4s;hzA_;FxxA8>p;Ab|@)^40o=1qPco_5X}F7~dR^743TeUQP! z)7=j*y4KcptDP99^agiZJ9oN^176fnWfQpH59R8+*<+S!AGbgbQU zt(`#_0-Q}!!xp@!d-_R&Jl|75;R$%q7LbF8GzJQE^l-Dbv2(X}aj@f*CxHJH@$&ZI zKSgLXCcG!okZfD+Z5*xL;pDa;Ie{Q6qX^w?rNVa&x!Gkh+#e{MMdbVG;m$7p$fh!yfh<~ z^k%#n5pPB%P%ZFaxXk1TBnv#1iZ`RkLQja$l?(-3k!awGNP|+zGM>rEfh&R>ct$4U z!B50MZ>a>lnG8t=x`Of&2;fQ%6iksNf-4#YZzd}X-jWC)9a#oEBN5@2Btfa$AR;+BZ!AN8#*#=}OR(9K=GV$-qJ*M5w-$larB@C}< zMDFPr8S8J*Lgk(|B$N>G^9O>D1in_l8{^3&!atXMAk%LoAM{QAM)EQ3Nci5(-%7qo zy8M?#A0pNu5e5r0A|$S0VFrsoNL8Hii7OHiiA>^(1cVfs0-hnFNe&1? z85!_QhCrK4NI`1=BczxDFDDzVi9%|UVPck2kd*mzDFw}xKC_ep>*kx*Vn``jrk(Zw zEh+T_Gz7>ChK9BFh_NU(sRL3jueQ!p}u5R@DhPazQT2v(v1(L|yGboC2_1kW_H z@Bsk%+vh&ns7w?-KMn_z?15#+AIlziLa?%j2{EIx2MA`;f7LLhk|#hUf(&Aukr7i( z)*dm{ffsjO_AX1Wy8p4PPOGZs*DpCW|GAbhNWKrW2?H^J* z1*x5gl!6+Vg9GD-^2x&aC@@__B7nvFHxa_5hV-Ne zVUy`vT~kAGb-V4}cAj(_Ye`)@FR*_IqE1lT<=ZPf^lCEpMp6#YH)KE<$l|HM`u`bT zATrT6L=rQ7LzMlE5d(wp@5-OC&xy%gmtiv3C)11o224iZOy2#!ix~i9AW?x814tU! zHi4)d3Q)%2A)Z90L4OeY0;j^u$bkpog$z*rWHRNC{@~JO0pg&@%Hb(;WIPp+AymMD zQ2=Q}rh-`lwLs6{n#h32fl8L65|M-y0)Qx>eGs;RazmxSxkv!XPyn4ngDfhD;epD7 z%b);q3BG_BB{IY#Q9(K~FssNk&~B!GNx)2l3WI7SK}`UEWYAgYUpX?`N9aA25B$OX z1_qrBSYUAf!8Mf(8bkzt;96D=vI41KgpffcQUS^`lOe-Y7Gww#Wx!~X2w-iR!Fh<2 zQBg9mmCU@HCN=%PufT~wYw~r(47Lyk@(<}Kcr|0e7L$?AF!X?ISL8&w+W(fJNBse6 zp-L82>Zl4tVG0U25TVY1VTh7tKr}?9FrWycju}wv?~3Y4>4Zr|wZYoWhT1w4MD>p( z`|ss7!nPBslwXN!Dw$baQ~r^-hG~lLAIl`-8c3&K8Zti-*S{EozbmtW2sEQofKUOF z6B5=yz(JCZ3M6fThVqR*cD5`V>mJb zmb$mW3R#Q*wngnyq}5m=-xjsF5FCwV=&;UBj2o1Q+GePYg>|L^P!6Mb6z^lLD%7Hc zM~R3Eb;zpvdkmfIq%_T>LS0pRo#961f5p(r;3-sqHMpMQY3f9&wzmE1o#Oo8Y%11J=TatQd!0M98(;sHqxwHAqXLP3G@_mo7#zO=?SiUl|h>(~tAZq>o^I^2d~;><>;^ zStcuwK{*m>|5=3ujIjv{2_;PsvVnjl+5kHN2}zXd!qSQps6z||2>1^uA4(Q7Q1N6` zC6;o;lA2g*4NInB=|L>LgeBpyL>m!HQemhy43S8{Qk7UrZUPC1A=QFiv=^si?V#(JDbQ^}WW7u~n9f_eTF$CfS zs+ou(N}1@yzX%#8r5q*&4Z4Qf$~p!UEWv+6+R>=6XPgRRd;U3VCqw)-h9E*V-mgOs zfLZm;zW4_iV)Fj~T^s=!cNo?VGW&kQ*g>v8*gE_Zy3PWGrvYvJzfIM_WFO4b{Zmd3 z03C?D`)8yapfdp>h_Z43wa78Jw;$ua03e!R`%cP%{2XFTKK;xv;~zy;z>5%L_5#QE zw`GaK44UkJHsTh*u!$%GHK|Z1B+9R$+#3cvOh5#POh+A*zrqz*?0|KMVzmv{(TLRy zSlv1S@t}q^!u3tSBN)w&#SR!mK(&E-L?RIpErr!KSPjPD77-1NbzWliJl2(o)xuZ| zfYJ}BPR6=9vFYn@3o z?IuHAV_m)fp{At(_ZSrR0lCM1ZmeV6V=@@N^*6>kDExPdmdr%teed#j5&ILqb@J~2 z-zZwtEe1JnAOjY5gZ(?j3N$QGXu#nGE*OrgNxWV^c)S1y@N+K~(2}5Cz->P_HOEzz7~fLKx5xB!-s5=yWuc2&HAw@Fa$vjr53w zhRmSI0MW4weUH4OAn#DS9;Kuinhep7j6e~@&SvOQG|&SLr$9#nMH{GnhlZ3O{X;`a zz|cW9F#|)OH6Y`H2J-;A1hzH7yT7P)CMD7))jI1>!roTdNq9E{NOzuPP9V%tT|0A^s4-g+`j8WGqUDqS1t?DTGEuf>1an z0*xX1(fBx&kVML47*wdZMTH?EQW?-4y+cerMjRlbqCj{Z90P}%ff%C@RVNH{0IeM{ zuYh$1pQ9mgN#DqrzRc0uW ziS&p;>7r&J@{SR`h^iAba0F>Js*o9K9X0$=?k6}JyNn;cMpb8QJ01P7( zsgI!qkvRgvmQWuiL?$AwX2dt5JwkemM#+Mu0gnVSf?#RDcgRQ(kXTJLf|7vr4~>~* z02OqsQNtZwgNO=dM0}!T0IGCRa}F67hWU^5ortsrjR|HL=VhcCvL`WZqy1Tj|E{Ko%`Tv^fdLKdFUScC|A7av zrx$tyh5LMe!$>jNzW^UViXYmO3ju{c$OW*&pCx3j4uKSKH4vouqiUe&$UjKPT+PJm z$pFU07$(Z3yvi?Z)1RzzW_0n70+`^%hd~#>L;7twenS`k-NO?oKkSf`#cFM=ro_Y- zF-$Z>%b>eNCYW}pq(#a^bUzLJ11M55U?+i0rop9v-TSC4$4GWS8$j9#HAoqBEviLP zBNr_Nrd`PdM9Y8>D=42eTqX^uCAdDMohb2%>J==4n1G2e+KJ&1N3_!fRD#jkSe(V! zk%P3FVH~5n5raxd7)^=A3|PI1)oKj07S;V29S2UAghm1c2E+OfK{F`zz@QM&9Sazg zhtw1V=LVksxaxEDg96 zWc8rfn+d=CJ;VZxk#ExTyE2~?v8WrF=&0)a&k>6x4Upx)z6BBae+jX`_9`$h!LY%n zn}C3?NjmvmYcWyd%!uV@9sa*SERb@Z47EU8GT=A=0KNdU0=b|68EiqyN16c$oCFQQ-wHER4>rjBa$QYi>VLMNn9vZ6X8xF~hZi;$4KXos3^YUp z8{z(=@!WtAo9Ng^?RZ2_U?Z`yG0m6=ZUQ!H8hhx}gs5;7Q^73Bgvjq-MQ~$cp$XV% za#VW*uK>^!6XK+?=M&f=8U^Kxu+ik$*y~?KRD+l^2xR~$2k9kjbTMw(-z z&}pbU04W7~ssf7BP&*zQ>y5gk0dR$Cw@1bk)r#17b!_ZB1;JZrh#ZR3P(B3&cR)Qt z_5>4A7Ye%5b3%MPQXj+Rj`Are)`{Dx)Q35GjEJI3#-3NC6aasrGErQQqC^`M+ad_k8byf! zo%}_VF)1%SDau%DqQ7pP!M}-?Cjl)-29exUuru%{p>DD?CK_bI`C`90&;o2u{GAsB z80)`O2TU-7`Fyb-d;E6+2ISd*&liJ~HRu+6#u(UZX+|Xi4+!vifU|QTh6AJ{1D}K( zI5Y?Gi^xDnS^Q~eJ*0!7<9mJ)V^4z`03GK;1V?5-ZNk%_p#6UndJjS`pg?-qF9V%e z#uSK80Z4`n*8)Y!p=Y51VDOuedj1YcA#-qnsGS~%_hes`5L^m+l6O?&JwJV~F z7#2OoEzdab1JN6dGd)m=k1{!kMnfI{3||S#$e@}Ytq;+5j1xW(oPnM;!e9`Plnllm zv5gu049eJ}`V{3hkhTEW0P88FwLQpCJKG_8@Rq*J_p@@s=tPe&oBiaIFJpuX$ z>J?+t0*YUdelTzr%9)@kQ62_qDIFnj5i}B64dbb zFcCP5;hU8F4fC>A%~VBeVu+$7a)c_zVKn*1a0>Xr8gSYNat^B`(2-EAA{<@-w!HlW zDUm5mNC|tC2l)M)pF50z#v~%@<5x$2fuOrd`aUTkgF#Ba8i&6NnvkskfPjEc^nil? z0my)Y0x|moz+33S_fSR%Oo4!iKly_rO(1wh0SW^>(gV1UAO{vST_7R^d!`2f2~e?6 zED02-0=mej1{3w1PMcg zg1yTBQM(XOE)zs3)-Q_n+haZ1jKFTx8bSpeayKCs4z*PfWXrHX5G!MXhabV!sC~z< z2#}OmuPin~kzti0NSYC7jn;s$uBaW#usIOq&g5tQizs_iVq{W*s-k10qGs}gfAhzn z>^}_40t^py7VKa0al%nE;L~CFIKftxUw-IJ^Ov3eyW$lMp#q#DEI`q?EU^0p z<1hqR^+)d`c*t<=f%8$I^jHtzByPe<{COZNR#*be`pYq#C@gl3hqCjJ=hA743mt zW#8uYHxz*J2DSCd8zSh4Fv%fUj{LC+49^Z$4l&_&R1Q%=gw}r)zky{i0l!Va zQy76V0nK4{8ek(48C*KbOd^IfdeSs@*8_tyMtNE!CAv2R8*#_rX%Vh<0z$-yK`gSw z#?djjZKOWz&W#B|7!kB+Bt8})GW-E34~-GYSe%KCt;Ftuz{YDb{1%8;fhi91?;%Uz z(3|8-ofKJaG*Q*kQT|^=me4U^fM@%e{r-!1e=_YC_B)982j0vHsEEmG`>v%XmD0?} z@|T_d%L4j4Vub8w6i}it6L6}?Yj6QMprNoh6m&9!Na*^TlL6kH&g8F`o?>32NK zc#D(<=4>KXWh9tPH%xT$g58IcthnzJF;O@Cat4^y!awr&%E4fkd4C_+p!ls_s9KN% zV&p%n7Qix_pcZ~5L?@W_7*YHyp^Y`Ae<_Ml=PybXAW8}4LYYi(K-T_S<$~Sx#c<6c zMm|=AV-?*5b%|93NUKqoE>_r2K=>%rj5u+zih$uvN85s=L<6+2A@|sDe5}I4QW_IT z8f-{98f1nBej|NgY)n9%)IbIQJ*5O9OTK-I-(~frO37g3dhPYIV4ib6sL@UpNsRbLvR^}#Jt6hd6V4qB+qh!F{Hk)jaX z0B(_@kWq)cMH9b1C^_c$RE;-m-DYRw`F#d8oUI+~q&L%TJsm+Pn=C~d{W(`zh)ZzY z?&`h?`dMH+AQ`;rHg@{!m8F&Go*sI3?kcX%ZmurS55dYwYq)sYxx2Y;xAwHdd%8oS ziM|~?!9%|?>uINI2mKl-C;|FM&)VJD1Nuc)J$F0kw{TtEK`0U>qH zV2^9wZ#6lmtkqYi=9%CVPqTxA2&Bm80JR(Gsnbb0z2<_3*?dtMEmn@jnl z6<#ku%fy`m4Q1rrpU#}u=*1?qoo;Q#d9sW~2QW9<+Jcc+bS-nEC2lhY!qBm|;^2Ev zqz9b$n~;gYK~>cbGDbxbQ>Ns%GS{04@Sj4bNiT}I!^UBZQ90PaT&C6lqfCpo;(Mtn z=&;k7D>zAGOtAr22goczQ@rXOBQG1s8_&qgjmay*$XjrdIq!mRGb{q~9%kePs}w08 zn&FdtjJ)qpGw1#Mt<72>Zzv=0W=vi-MqXLWB;EejX4kf2y+lUdotV4?M&2wX=1DT> zVN9@^W3RG?KibsZd&~nmJYs+>I4dzsne)Dtxz0>r<^4uvUX3G}CrR`MV-+}kpQI0O z->~2k(Ncpi?%K6$<{0nQuX_)J0m79mfQM`O&L?v|rlj6wd_?7s3WFYxz8l{ZesouX z*V5$Av*2Vj#nE%GAB{h*4SMqJGt6B);>zvRKa>+>&yDk4w-y!{!Bf~jcm|D8?~dGU z0HWeq1Jc~!SM@H}UcbrzCIB8&(_fswSPQ0MHe&%3nyXzh>!rRoC16#FJec|ejIY&$ zp3l?sw3Q7P*w`3$JwhSLqylQ(z4EM-{^sVRK8GHIww14}O1jZMCRT3^y(?e0ssws! zVz5olsQT`i(FJ?s;2zZ|KM}9k0LIxfCg@p1&(vVup}T_eUGt{laC3n)T3fm)xLvbM z_p4y(GN>F}qj2f=_p9qhL0MvR9b1-m27BSZA|Gu(81WM+_U(_$-uu8G--w2pz_OQ* z%lZ3Cih^Ffg``vY@zGf_Wk9Ovm50o1w{)4~c8Cos);Ok6s_yItwj(c}kDV%lzmT&- zy3xjM#e{?pT#tJO-iJPiKdka?K#o+OI$07GU*tD+Mo%J}Sm(pJw-)R#w9WrMq_|*Nf#? zxlft{?-uAjSQk__Pv_PSuB#r-n2fg30I zy4g2xX5R6@%qxd;bEWw>pyVV!pIbn<)SYZ)>oa-Y>FEs(Z^wb&;Z;4tXD@rppUSSC zUc6c$>{y)fkm1WWPzP}aC$no!-g{Z;GzChoDuJF1RF80bU(M>~aJGmzll*SKa^14I zyAQftOxK2rE4LI{UGn7q;A1d&O6->7Pv7hg)!%Otx=io*D`<*>OR7qrHEVVVTlVIs z3gQNI);gARlb|={7MDNTzqmSecuRz2Kz6O*wL9&)lJ-+Ml^3S-fY&%dT6fs^u>ZsL zRzjA&L(_7<>@G9dYaehCo~$E_Mp|<&yOnC09n~pt{;)BYzF~)>h66mcDI9T=K0?z<~!ZtCj>vu@MDny$VD z{AE>KIO$gL%f0@#U?}G)nH{aIeE3=K$*X&27u|PsgnS)NeLYt+8Llq)Re=}%;ZB_H z!_(%6Ug?dEZd!0t2Q+`gyzON5Aoz+h)XaS7^rNq*l?ntK^B#TiaY;6S1hty0rx%rg zaqn^L%@Oa@pBXA{Dtl^6OI-ik&sGAs7RkPWZUZp524}KMP8BTlTDWEAJ>#O{IoAYT zZ-@&RqIH{$B`Dz5i8rfdC}-}e+V=2p@35(z0{?>7mrZMMxaI1r*Tk+429-P>G4+w8 zH`9aJ_;#sm{(Lln1(%|=x^u1q5%kYIAiE^Cpx09bsv@r8zSVpqztELpEI93>-rFk#~u}! zJzH}$8J5ph1n2hWrG9J7e0!%V&e@{WmV0f0oofR(&MK$iwDL#|Ck|&dV@<_llQy*l z9kY8&<4U&VuB1s{Oj1Pd6;-?DI@M^P6!vxY_o2a>~4^1kW9;Vkki{f)5N1aVb-9bSJXYx}^P z#71M@-ry`py79W2)U-3n#%G>ddh^zI^sU+FHrQEZ6sKf;wzx`Qi&omnf^g5x-U}Ag zN(k{M`}@s0i3NT|$Bs+!=xa%l@ljW7&s>)dcL3Tz zE!(a0l0h-YV^*{LJNJz3=U;f~Qde(waEmgl1I_#3!Wr6o%9gLo=GJtN)_g7-A7f9A zmULd%Ptv*M9pk#Y^^&_((a0jZ9*N_^gqdTeGQ@-Y@$a(cM@DUEe_pYZ7SuncFkDt| zwXtZ1TWqL@_Ws`C^AD)}tBanpU7W|hUk56ikFMdh@JPWc5y?iQ`U?d`zPdW1B9!Y% z+MH2p<{^z8(g#>-Si@^tUzjAm&w6c1id~hxe&?T+ zTkr@Oxo^=(v~P%ZZhfGcxWBKID1A~hq;+d_%`*5s+o{mzn0G7p7P|0u&gaV8vu8+X zcd~_drd(W3{;l)J*nBh&i5d=Rw!M#xcXhHiXp?x8E@6BAn3cQOVTn^)XFV1s;@8GS zyRWOf*A(`#C3v?$`P+= zD~>A1>Ml2VU(~=cu>U4luJN%pmPy-sz4eGk!t)Jp5aJ(c(UUEnG}!l>+kK?RKxLR{ zo{cYCYG7d6BpIhhzrH4^-L{wlN?H-E7VZS4;F_1^Vo1v~AAR>JD5U81bK-2_^T*_7 zyUyjy$e7F7ENuiVi?4#OmuppSJGW2g9=^>zJ*nW+!Bq>Ax1FoZua8+rPq6u#B5GN7 z?6Ua+5tEfhS_%?%4K^ni4^3|?zC^C>R&MfJkMl5ba-EZ7>YucB34PRYy@`zK)kekj zXYoG%@u0ceqEzl5SM$1aHYH<6K~DqWs!IFF{fK<~{r+ba>K@W}>>873D-QG0w6n@d z^3SjSawW%|N34-^aL18dsUfe?II+;nkPQRFU%pyDQtSC z`jP#0T}QYbUS7^pl!yc9yk=Q0NASV989bkp*QOf3w!S<&a$&A-{XMz!7O68n&`VpM z3eP%gDpK0?z%QQjjXrltSn%Tvg4>CzO!~*u^j@Qfa*1s8gz|Y!Z7#|JF4rw~USEH$ zcGs9R3r+8fRbfzhaYK6g*R`UO9gQ5-^PA)gBu1(o%m`;@C=OXTHATLdGDWdDaB<&G zCFl0&HU}AkzPbi|T(N)qQWh?av!b^2r> z_vmq0^Em&yK@{ksnnN)2$1dW-Z-YyUwbW{i%9@RccyOeF=9afY>_k123A~*LS!l z!hh&S$dS@Ln=?|4B|S40T(b%eyxcXU5$-LqyGzvl74IpZi>8Z`UQl^NeVaqHo@cLb zYLc|S9-5N*F_HC(tpVSRJ|&Lp+Un=0bPY7Fy6c_V)m!}lB=9%IQ@@Z*55#AbUs*b%zr{1&O(#%+S*s|u%vNJa|GiWbf zef4zURiH$#ym&_K+8|v-@3juXEZ z^mex3g;i3ILQa5TY?lpePq;h(eOlns*B@0c?tkXdin{C1xq^Q^U65_uY3i z8oC|_N4ifxaC52ua{VJ`aT#5H4<7=HC0L=fU2acCewh4xykxb1ajBXWEmW1Y{&WQn zV3zbvPuY7v=i?fTo!F+6I?pe0KYwIRLQ91wy*97++zQG1JJY52MXCqn`12bs2_jvX zD(I)bq`<3ljfEwDx#g?~F8m$eb1u;j7W?rntJ8{pCQrZ6=dYs`E`xh<&g@-pL@DQ- zX}}0ssAIxz`uelWtd^5q^s`;Z#CaTWinijNvw04v7-*k4Xp^I!w7W!*kKMW5ob$8Q zXKkf5D;F-R=a}hke8fRLd|UGkZPTQMyxV3ijWUibV26x$T)FlWfr0&xgReL6Cjm%-Ww?E$HGx^s&T5CIj^bS;#MYY#T~m??zIm4C;PhYkUSaFvKg0}o1Z!!)^cl# zZd~Dqg{ey#l)v`fIJVDKcvjjX3zi zYZC9d#~rl!%1dc!!;j|IinxihRCm4{k`h=FoC>i04tGklT8o7Ba`9QBD_@6tU){nU z+ei$$y>8>+zQBffW8J}5&PvIb_A2V$yPQ$j!1jEgO$R(E#YxRWoiq=;p7 zIFsbqYoBn8Hz)f+cA>JG%Y2IEHUd z7uhbHWPLs8bwj$xm8lm+jg;S;2h5#6qE|NKt#n&)R_(N!;|E>85>XMgIytsaF4bL)u9$tYZ z8IJ2DjRDe&4e_x8fz#mc%bBDdF-E%e;+T2%PFZ~dLr@}ri*i+BoFx~ea2d>wJ}ZHOek-zn)K6Q z|HU+&J>yp{t1dqHeAWu@lPBP-?9D1A84}V>8v_59ZBa_^^2BWoCLaB)yHXSM)GRFve zEtPLah2QlMp2pET&wJ&5i!W`(5+dGY*1Xt^qnl_#o%-8WanAHw9QZKuh4PjqK~Aa4 z7g=5W++#CT4=$(^&OKFi@Vq)B8K3{c@waOajdoKSnv(B|%{E^9Tx$BoDLMNyE=wK_ zW^1@9Ft};#aeEcFufNOk#OO6W(fsPC58dQUI$pkX(7YqIXe5*izm31pZE*K1{<49< z<|)qYH3l!PyYnvvw#1V|(YFdiP7O-0dJ{OBxvwtx3}3USLi<|U*6!c zF=kk6sKrQ6c1&&GOob~0fq*15-oN_A?S=?^?d{b4qjS84haR=ok43K$I54Pb8epW} zCPvI%*itOyDi*M+V&5&DG1;CYdE!w|rTRvvUDVE9*vLK*Q`oQlddO;{6Svjk4<)XK z-lrmW=+-UL_>vQuWMZT|%3D>=OSjXhNIK(h#eQUsv&A#fD0MLW`73$nl5_=9m6hG6 z#q;F%EAQQLzsYVfEpt{d`C;3EZHEhYPh)W%n6B2Ns_3wMH2Oo8ca*{WB_GsSYg;*m z^{e$7w`~uJJlC4hX zt0?|YrcE_5qG>l2cMZgkUVi0q!K^(>U|Ds!+1$hH3%o?!+7{M*X16-^`jOu7piE13 z=#GrNFB+Qm&+L)kI%9dpmhkgO#x3YCLfy>+tV|j|&TzIko_MVa7rcS%+Vxpu-HQxb zBx!zNwj&CfgYrWz`)*b=-ow|{G3SI2Enj{2Wzhvb?cSWu?f3oP-ouq|P>49GkP>3O zoGVW*NM*XQ-VxIW-D30BRp2%`_RdN>yZYE2zTgAfRpdof6feJdWjZuq-qsL#;SJt- zFP-;w5qGqaFS}EWTJHcg^0rB7wbJn-J3w0Ef(7`C_LZ!>v5{YFK|+IOf~{QKK*a{5 zDXB4PxJI!`KwL${c$c``?P9lD_Gq?v%=lTJEh*|HUYeUV)y?FDOwI)8@(-H7`%#rDF5f+uwbp{3`)T>gXHKQM3)d`&y;$LI-Z_7_ zXj}1FtrDxt4&qa-q*l+t38h)kHa}r+d>+zQxA;w-`*rpXF7J3rVEp5X4BQHz|YH!I#W1)eMZq&!`G zPKVpICWWY7PI(`id2k)eBb?I`6yxLKM_p`jy?XD$HCM~y9*~{H9{|81SI6l}HS%2- z96-;t>zjq6$0cyLwyB@4#tAsLzZ1>hL!+;iGn@kki7q1EOay!fOM%y`axK7hSk0j; zSe%Gg+j3H3=ok)S(Kd7*p9#1W&iA@5r4R>IpPs!_-lyn#sVdI5=85cHNsi!)X??Fg zD7LAanMZ05vIm<$D<5|vxS%km`7_8NMDG=p=sVt?@^QM}e$Jv5VZ~`;jpz5`!nMTr z6#C-YF1E4&-s__}z4^_DMcG#DGuUw_79G{W8HegD2^N713#N`FhUmps&cNv%FYLD- zRXcy(Tn$IbS7A}2)6I%X=IMoOomzG#Srpd-*#6)h=1YT>GveyC242J^_lbweO z61{hB5e9dCY3;HWH^IemRUG$@8;=DZ?!9a9~04{LvPzVq1 z#IhhWz(H9_Ik#_kwSnuoAz(7@ZE4eKR0Cw7)hdw8QM~Uk0hg!NHY*2m2}CNHeH5Y} z?fX!w6D&CQu9|2YE>ERRqh>E)QfDih`IHsZdhdL)qI|bR24Blr(AP&)(3m3-LAZN! zJP!A1)I#Zm)MZ`Vi6zeM$%|&PzoW2pNPZA&sVA~ck1E_HegsEI`6>Vp4L|v7O5}&G zXd9gkgwIh1O0M+vLWTmSn&RYgb&5~$v;wb>Zqo(p5&%c!DA5=3igOz7Xz9!axB{=I z_N$lF&6w(_t)_6G+?_(3=7v|}14{ucRF;O--+lt?6_-?*7 zS9I4otM71Xr^?NlW&d^`3lIPC*KOL$`YcM<3WOpTkE*b$^U*8M@_ONLa*2igM!Hw` z&^T}CKWI^zE@V?(z|Dbo+sKK-r`-9h!aCh;8W`}G_-EIiN%w?mPr;Q|&H}?4xxvhb zH`kHXCBBwZ4Lk=-pK+Hy>tX|vroDNQH@io`?m_paOkP7cdmc z1zwgwN?m?&iM8D9&8FSjoH(CWe49sV*p!2P1m&5yZb0q26)nFS>MrwGYNZiP?55u- z{T$h-DLgGD)^@r=`!*S@zMvGbEE>13v1wOTmCP|-g4^j)m!+CDb-HTxOUutS6i!p) z4!)b#=d!(%3tIA0xC7?1oOVb)GvMLMkm|EKo%10wesgRiDa=%HZg1XNwt?uvewA4v zduUh6f#IOHI8fPbXgKk7;0D>Fz7?w)ns&BD<<9S%njz)fouezy5|Ng@Gxe)IVY6k2 z)WeaSg1n4Q+<TDyGd`%AcFFZ4Qp>boS1D7ptwpQ+Mq?8rzeYo10s%m(eMHEYVlUW4oIodyZp= zF}?P2&dkv`qjTO)@9^5sx;%Jlc{`NainX8LVLel09@mdsrWbpF&Df}oKhm$tsiwqz z-d*Km^>cCM^Tz81l@^_y9o##-z?jQb#q`}_+YZmiS+vEO2Xx8=uU)%VoO3!Vp^>~d zHr_~HlK0?(!dPHp9_C(dvwsUWeW#Di;od{x+=OGfUgP_|?j)Ga8OWJBV>slEz%9XD`_mBkm+WWWuJ=$-N-tsIH z7STBV%#Z7`^6^XBM}TJW%GT3r+)v}`elVxf^G#tz)qRozn3UPNW*^s_AFvWn+8i7c z`f)Y)oU!0-BPA6g?{f~?*sr}khu(1TEIEIF!Obt`Wg@pX6QA?ldc37lU)_2f3@Y|iC7-sE(ioPBBC&aA#gGB%Sef)d^uiku}5-J#|5;IQmi|yJA#f zU>vwIRy}NQ@p0u%yrc(d=k?UazoO~m}T0_`;W7S=58Ai(bV2?U~P&{ z%G>8^^0oT%8ux^_cgm~Lh12o2krB&|glgXd2-uH8D@_c)+bN;Zq7KBc1LxvJnFVU& z=U2OXPfzVl>f~FgxW0yC%w?t^OPg`t!D+`yGc<|&rf)bi(7A(GQHOTJ%&oQ_d7q(W zwwX`R`T7k`gUwE@P1~ZH7WAc=l5QSM{#dv1PM5`Ki6*z8Vr=~Qhu+FG;b&%5+)w=d zmdiwKW zcxrb3)@zZs67}A-@z-}m=xqGt{cdelXarMa2;(-2D2WM)LUOZe_^KR*Zxz&{~=9tK84Y5pnZhASpR$Y@& zaKB?u`}$(V=6!Pq2J1`i#j6jM$0lz1$m)8r(L+oUA8GZuBFjlhL!(7g%DQq>Rs08q zUA2NHw9xRoZuJV@}qYA+u3Nj z-D$k#iX7`-CN=jos_dv~F4k>f|Ts@$Jw?~r?#I9PE}D!Xf@@2xq*rB5r~O*s*{Y25EYS&-%|GY-OL zUq1IijyWkJ<*K!pyyn+@VCzd;{E-&=dZy1*qteuF+P0o_h3*aKdG#zhjNEBw%NC9t z8=$S9!$0SWS5;yvk3Qx`ef_$G)$RPV8}B&H4hXTA zXb1u(NAYrn3*WL&_gKZvGO{zL&3t~0RWG99&fGAb+uKdtdp~?} zTHX0ZDerji@V3sQ_MeZb^|R#RA3gQmI;$>?b7NF#m{Mke*L;nleRd{eY6)`oV#jx? z?Xv)uuB4cY&;d$nwa%WEaRz*P$stv_+$tCe4j!szo{B`VZKnEUfVGY;ouNNvTH%~sVch;fP!hXpqS=U}t^ygWlUDQCCgxGi0 zpCmtrWjy5-o^5C)cJRr3)!{konJMXKAJf+$)YGJ&!9pk1Va; z@c$V5%BZ-Ord=WgB6x5M5M=O#5PV2*Ck&S0kl^k%NP-4;m*5cGeIPi4yF-w{b|OnIRdwy|-qlZo9fsV*T7oG5S5$yoC$2n@%Hu6=E`8mjoGsfv z5JL)bXxOPV-`d>3%r1K%&w%r|w?!h|O?9v2$h|IH1ovaieW&N)vqDi6IPul!6Pk^! z!xtN3jD+1b4}6QJtL*RjFYyi4K1|(Ek!V3Cbj|e8ndOKtlZY(nRXn~wPF1H0RB`Gk z|4vn+K2TL8Z;w`vb&nK4xNMv|K)o$kh!kWKhE3L3E(bCge*%weA@>dDLpGMzC4@xj@yhEutIP$J5Wg08l8G&#UyTXV5p5a zsK%rH%`k^t){HLQw_^U)Td~?ufEaB;Z?RoME}}-@w%=@jpnBE*rb#vL3oH8b1dpW} z?k@k(r^00GT*;9gM#>%F01}t@F6qqj3|X| zjA%>!?GuHY9MSaB77n3=+s%HIYg<0d^F&@!9)Z{qU@L3|Z^zK%De?XN$LihfDzDp) zUCfgVKt@6H$5I3W6Rsy*YK)RDdnDMo-4k_BI(4LXWSX5OZY)pU*?gBbW?7Syv#2nO z`hwo9pi-3E13Yum6rMY-)vJ8w)Z@q7TJ}}VHc{&^PnSS@>wZ|z!og+F`&vIak3?lT zh-oF1P8g+saD%zjXYNab0X+fWjdYG4ZQ%S^K~Td>VctSViSe|;{EyEJ0`EUk-=VXL zot}{oZHtMoKbG)Z%S3C=gY*>4c^|&vE|o~z_%gIa^0Ha_^~%hX5sZ;&%dMX{UQ=0~ zp9q{Sj{|?sXwC73uJDV@J#>1n-9lf$f>z1VYTgRmSG{|i3fTu2*t@fBMP){KsqMg0pppRcczjsI-tqj-u3RN8aiJmRa*F%?2)1CZr+mY%uh z^x)uMfnY|Yz-vWL6%WFePVmVqEA7dsn>&&TJ{cBH$#HE^QlNGzbUyCGSCdX-${;3i4 zd}4g;HQDx@yuIun`Vk7sGlGe6+W7wn#Ey-RaguEpA{9k`th!RvRJ=1C#Ww49e*H(_$#%?RY-i2z!I}2+GDj#)WZurYI zMy;Xjf88TOIy8Q)ysq;PuhUZwTsYJB55W@UL)XT?l={$BYp%J|`s?!Y^&QmFvUuEG zD=6v7lmCW_={G?-2(#)RHZO|Oig+Ah`o!O^#7`a`9|My04zS(n^6oR_KkP;au=<2* znit|P!4buUuck2HjeGLHiX~9$?#dVceFvoY%5ERWrD`LIM9AWaf2Q`gKVMAi-dcdU z`j=3N^05s`azmO>^$+valOkjT(`4&b0{3j|Z)|@i+pjD-S=4d)%e*X!YQ08&2j7+c zedB+tr*f$9r>}0J{ssecS17w<#y^(!ZClx!2THSX?q5!8UIPCUuGl-sL8w>=?H}4H%D&j2fMogS?fW4h*rJiB z#dl{!MRn!Be1>B2UnFzIf7^F3@Z4 zvo_YupZ8$nFHIZeDV(M^dcE>42%5j`R@+x%p&cIf+^N}2^Iu;%_o_E(fwGEkdEPZ;Eon_) zuhtQg+EnMfcL7}MZCnE)@8BNlm)*y@obR(kCZh$CakunElvO0emVECV@)G4R3~sD{-25LA6+Cvw+wcdY08-`d z#37zh@;NyU@gcYJ?~rvj2dZWN*z@B#2$)>5cdNnKLlDr7j`=nDZ3CX5CxBG3yV~ww zqvT2N+G=_S&3SsKm*orC$iq7;1d$rN#<{!ZLRuO=z3|6UlpJJJ%f@$AZ;(~n;njD( zvU&splK)i`6_ARF=kfMWv+qzc!6amNw(R30uXPq~E#D{11jGM|KLVt3|5fHal->gO zPMd)jut?upQl#u}J_$soK;y`r2DL9>cvaw_jXz5W8(}E@(>pc&!r$LAHwW&?id1pX1J9 z*WOX`y#ZWz9>yjE0bl)fBvR(dU++=D@V?z)YD*xzb^gS_86gNrd?yM-hC_$&UpQp7 zHZ;M6KfU+jO(qx@Q}0e58H|qyw%PAoM}*X^fb1?ZJ*~pvkDDQX{9!49n7s?2eV$Bk z(OtNmk%NE}f33y@q^dKO-o*g&cC`xy*If)?WP(}U{O`1MMWXPW#oam5j0$FJh<#_t z4e}cG;x<&@y?h59(el8)xCFg#6ho7!dKcm_zN@%y9Mi=UcK?f9{=yvNj6 zYm}?kG5W8`CXg7f(UaSe#tr4~H#Rb%LF8&S8SQm0_X~Yn!aX-g<^J^CyCcR|Mu%I` z1LsYWZf_yleHS{JFJQL!|HNAQxV4D*=dkH^*(zG$6=G?>Otz!{%^LO%Fo-MgrOi-KC&?}re;n&ivjFnDPp zh4G&eW^g%qyh;@6q1op3u8j)zdF%ThrwwhC)}#Au$_!EXJ^C0MiVS|E{yZnS16*3E zm-x&dUU=M#j*pLbK5B-zU7YO9mQC0hA#ME?O)kPXzS_aYiI$G+IlA7t5*)=^gTBpZ zMiqaoPfPnTEQvQ-R}&r-kB|$TcL!iywc6OGkOpyg2}B&bBTW#Th1K+9Mwn(^3#SP~ z*67!~>{mjne4sm+fd6vEI>uUgVHB~$B9fzTwbmz?I)(mR^x%SnRN z9{DEzQr}T!#I0hsm5^_kNNs1ABH1|&EYM-nktQxdwc5x!B*QVrY{Xz4QoAq^up;}E zN=yS&OWyl8wLfgv0yULCq<I}`< z#R)(zsGH-Zy)4TKMln20o(khJ54U`+C9REi{j%XpII9nq0^r+Dsn0ak3Q))L+(+@u z9a2&JS^0V`}0zcnC(0pl?ju8C)gPix}+QLpw{( zF_4myt@72uwanXZy)_QVvv7ZQ!jwD~8>`9y_c+H%PO2Hjx2F$tR?Tj!nIOq^rLK@wXHprR_)mIby( zQU^qM$u4%%1-=EnB?Py%Eyy`kC zSeWkPbRzOOH;v+FW6EYPO`VOp6M+0UsP^|&R&b*c(oerLlS!m6P(VPP+?$av{dRP! zB&-wzTYAVxR?E!_a>kip>_(|j&GFvWRlU06t;B`a6XawT`dJ@2iM>#3KbEYWSPqpQ zQdO-usS>@NX|F#=_01QtJd+KB-;-U&FQ#{1Fgdnt@~^36y@&Eb=&G5ao?BC$DB%U{ zLBQla!7=s`cra5D*9bcb$_gh3v3}Dyfe)($!t-|nk1(fM<$FbwRsV0<(~nR*8&+cH zj>?jb1}VefUmHndv~|l6^U^=#%_xvxH2&M4R?^i~OoD{5GQm3Z?xR5<1Df26nPdax z#OcYuSZQX`t;^dw_y9mTnTzNV&KCaQvv5P#IO*j zeqa~-0Xb45MK$^Up;7x#QhXmFSf#GRi=2%8ZEhg^{vfkohIJ2yUetjgm&co<1)s_r ztO^I#=7QK(qusNGxeF(^EyB+*9-w$iz|HzXPJBST>sTUMN15PuHuLd<@DRhWM6HPr z#$OoNOUpN~?>|ohIb{B^q3%<4tf`5r!KuA#Bf6-XT_*Td@U^3``FF#bUq{eErP4iG z*``@Lbe=Yd0;EZw7dd_Un-H6O34%$r& zl=Tan`Mfqq{PlqWvj4tqo4&&-pnGQpAEyDB`099U$C8uq zf^}JObNrL2jNh%lSgz)a{DiJEj-mQE2?wH1P}O6Ehx>X;Zsm8w>mjv94^8%Jq>qtw zZ&K|7Vq|wIY%eDi=b&EsZ4Z#13hr97>rr#V0&92c?d6q+XS;kGcy)jDCcVxUMlYHg zWgrSdHUgj|i}Lsf4khE;i~A!~-opl$ zJ8`YZ*TQ9o5-zmUqh87Euz5U`b-2p%eLLxekRl{Klz*kWs#tNIlvzC5JO1rRv`n43 zCFKYea%3DWk71+4QEX7!0JV>tY)_Tb>!q%x5QGD?g^I6f`HdOeJn8$+M7Jm+5EcH^UI*(-Gq(mwSK z%Lgd$0Qk-T?P!Gw=ZVRT`1wj04Hj^_F5pU#Ra)|s2YXl3^QMwbpWsA%hff~cemAVv zpHMxM0TdMnUzk)5#$3{ouL@Ne2y%AsYPr#Lr**Hvv`2iic2?18pau1*ig%J?y~hS9 zYl)=7Y^--I0g4LDs~+gPxObUGmVZ<=^Ty{M%5M(Uf@*%d$(*Mn#wu^x`y^-JHkwOX zod{M}*W$z&gY{`e;%2@HLu=rXI2$K9o2MmM648IePEO0MykBW%*!@+wQI@iVIF(oM z^F>G17nm-p#U=Bcv+0#x@;#K|mwSe8t9u;CdLA!efhP7UJl#)|)FT&;a7c$n4j!w| zLQtA&GttOSXAROjA5d#7nT(5Hn~xmaKSKvW7zk!=ax)s5Ynfyz%W#f4$Wn@?3dySC zihG{;$y%HkSc{=(W|sl?1IcF|#txh)N)j|<`4<)QLv9yZ9t+Ddw3TIW@cOjQU3?1*9ahchTvilys ze^?*FWuK9^;dBp-3ec|D1Wzgm{q7LX4xRFslam|k=X=OIgPYgv;y9X2ZpE!JVsi^3l{cQpv5;TnC3d@ETIp2W5g*bt^n}v9zik-*DXy4_m|bFd)Zf4R;Nd-`C*uKA zFFoj#^=nfuk(si6+Sy6i#SP}(v6^lQuSU#Q3Ug6XG?TqHO zbw7c+%$06@Qa$NdfFd&x2;ACVtZ4OfG>5s@xTU~pJscrlRVWuMekd&0X?B2xrE&y) zgu7}ye)09Xx1ufF2y>%{*lvy$$7-Z072VVe&?1YzTU~fqi$5SX>9%Nap9+34my$%5 zsVIGF#v-ZXEu?(@2$OxQFUA%@F(+Oao-!~1_T0lMyy%@AgGQE#4YJghy9=M@Wd13e z=2|k4O=P_yCE$eEwm4Td@^--m+e*iRJ1E<|(WM*ThK0w(T>4KdVY+nLgL*ymw?!2Y zbwL?&6B&UlWujZOwA9x>zC~<~7ppd@^(V0$recu3y}a&G5T=rpz7D<0lz%s$R3Bd9 z<(#mJKZYa5vYQGn%~Nk2*6gr+OgMR9m^$tF#nm5jYy+!f@Hw#@q-T#e&IkGW4KCkQ$i4}( z{z-O1ubfDb9XjK$&|7{a+TfNfmo%V>aZVv%?d_^=}KpwE@r)+cpdDPc+y@$QXgo8 z?V593WWqa+&3JO-Wh2Q`<+MJwx@Y>N%6(BBUZ$46u>Da@`nj_Kv-bD;rbSSY_Ni%AyC+>wyEizJ8COSS%X6f?;qYG*~1TDTWZHW za@ETq$y%!a2B{oXoN+q%G(Mdp`%F?p653n->xVMoeU zRB4k6{&+ zry|=na+3KU#Ti$%M$jzUP#f~;OzWuB7f}mzPLepue`(oEwf_P^aErak*`7yz zy8q;ORg=YrcYi)>2`8GaVrI9%QJGBEo!M==AbQ~`If5*`z&};$F}E?Q-ZlfxZ$T;N*==_koNTii;<2bCL@Z?x~AN3gr1yOL2e&C zDGR(aE30q>2bRH&#Id+-66a)?(;4IuP??;EIHU59VmKV~ikH3YJBL0DbahU5oH=5R zKh7PfJBA4cIS%)zo-4}9yl2T{vUS-`IxH$rDSbhpK}AH!2V>gY9Jf>#|264zWJvxC zvpZ7+ki{Di946-$!^gxxMh{pxzNr)N4N9}2QAy4O>r3_oc~_QXPvUsn&x>5I%20vX zD(S>TvcTJD^>a=S-r4X1mkP3QuXe=7Q4D!5j%Dah>z9%qnnuz~S8I0GHWwHQ20Mnq zHG4LlpDj+ZV?n+nD5lx4H;uJbp9cmd!Ygg+WkzPE$GNQ6O;nncviH9!jG;I2*+33TKjZU7ZWM;w*<3rS#wvhR# z;yjU?V$SKywy>-?f5lkAe+tzd~(*#}gb(hS}h;Yuz?I)5H!QA+9=N z6x`{dU)1>m)&$1gf(mp;1@*MlvAR~9Vx=3eb2zFOHotp!${@}I=O@6-ucp7n!!@_f zUK^k%>Z=NNFUCBG2v3Q*_TKvBsgMYt>(!2C%q`}3T4hU%>|KNhzjj;kWzXKmrd~0s{T6W94R$=4vwWwOj%1e2|nykxbNl^+xs+>$PQ$X3gBqmd$w&r3RFZS~Fir>s(nka0cR3>MRaPa~UGTuv+}4-i>%#uRg=xw@?uS%l#208mHO5TZOHjafJ`pf}|{!AB#Fdh96<&+kZ z(-VooMqhHt1YXb@tIX-m?+v=>(&b(3;_^vVdDmK(9nKM$C4wS}Z3rt>+HXPAKwnq+ zEHA%fnnrnU;Ne80Ioxg69e9%k#_F~_6e%~0Nb{A=$N{6JjuLfDh4729xh7UIY?^kR zMg6=9JX^(P11k&FLCKypaH(C8%;wBq7Z}-l9lP;&J#qVWekeo6GH%ni!0SJTuXL!* ziAl@X)3r;&80@zDVDCiJJ#^HW(^uu?eXdG`WZtBPB20PtAnA_V_Ui3apY;8$?lu>L{63f)2(1Oj;0tL^T#7o zJ;}UQh1r)Aj{br?q2C21_mU4Ox-9_<Dl9_UHs%eO$0Qa2`u!oGbLOcwYJ z!3^U&wO3?0oihBX-&#a_dJilpY)JMCLnb4p08kG6$a-2ip|B;{zA6!{&H@xSTVNpV zSpw4At@hq{HoMCm+ca@*&#cGQ0B>M{*p}DM4IDlRYqZ4SPBOT zN@zZk9>AO5X3JzU6zSTu-VJj>=*^GpKknsvwLg?M0D=rf@Y&lkBf37cb_}_8rc4lt zGVpaq1a1`c8za|Gv1;#Ta5 zTVB!SHNhVevJfCiVQy5#rR z$~<0*$-3;LyRwhk-i?JMZ@Pp1u8*MaU=~|dDzx}mzwwilX<>e$rX&&jZb7^2R`)W) z;F%XgDaSchX1zi@OjBm(i!*Jx628srC%QGV=MalOdmJS}Mn=9G!@AW(aroaXr67VDV}pY!=55LdS(C|aZRNk4pY<0|MX3f{Oe z#9M5La1KcG?PHQ9&vdm)8s~0#G4R8vo9K8iLp!^4SLJ2xDtQ_=5nP^SZ9CXk{z6uE zr^jD9PAfq1vX#qwx=&Dc;arGnj(zgtt&eg%a*wlGkFIvBA2QTjM|?0M?YfYg)2nq6 zkhFV#tN?Yaok;G^`C_crFM#_d#~r(gKa(?r-9RCB0I;%ih6h0HtdCc6PBCh~aZx@V zpsR73Z#YM~eVl38t_5i3&c$4LGcJ9Pf6<^Fb+5H2F{HULyD_wBTKj2%z@=U4f7rg>@X0kSq$ zTut^<=NP2bIpn~CC-{s?b$VG+gcJIEL1AyQ$(wXN0Oz~*w{hfCJkIB~&NAMr!kMI=-=6WUWfi$O|UPZZ=5_WTk5z0mvPxjN%Nuw1H=e^etO6?%Kv80@7lJtq~rW z>#m>9m|*28b`E+^nAbSV*MGfEW6GaRR85RrWA9J|_RN@1EO~rJJx%-As_AS z(e{4!Ibp_ey6<~b`NXi0UbYF0*4CiTo2JNGF0e^yBZ3`+j}2JZ>s8G*eO&~;YrWO~ ztuzx3LtAjUSbe|3scms%^tREN$CzoN=u%IswfXI{u9-zm%e z*2BU|kK#{>Wr90{R7}VO+AwOja{joZ3+acmJU_CA{Kuc8k3a7Lt4FE^(?z`=Ipl=g z1H3t5bUBpT3PK+-eY!pfGabQs=rpdhRNptM=6TJY>XbkRq}}K3W$Wgw+kwsSUXQ=v zqi^Tj5DXlWCwS4*op58je(WK7eUQKZxE6FxJzV6122q#ULD74XSB;dkwa*S`? z`P^CN|xYXRLg(Ujo1UGusEXVyXb` zbH73%tPoa*0WiI5Q>1D-PXY1g9KJK08Fiv-oigQp4+tuh%l=PHcch9dL3A zN(13UT&&BLm5A5hT^~x>Q>#L}Dg$<9)xVDw>ACUIm@qGxEdjWD(jHf@oX2#GyKOtt zbMkzge;;csH{h!-7zeZ|hhoc*yq9-06jV3WOPX3i%Vz~a%o_uzl(d|mJ5m?we+sUl zrwy6)IG|l~)C4G>3G20Q>wA%(!1aC4-uF7ronAu83f?bDToxCUJUj*01W&KJ@2*Ub zw>|D6ow|CAMEj&`(HsSmYOm6S79Sh#;?zhWs*Xx#61fq{8QW^*ldYpquZ0UQ@K&EE zr>EjE?LzaEKeMG;W?M4X3Y>+iRdStOefdn5{Dgd(hmUwyKSAy3AiWyyKxB9t&%FQx zoCmb0V!U#Q6QCTihN1zHYhT)4EqxYR=~6+?*%s%~kE>?0#ob?v46q(BeQ()U3XV&Pf{Fv>b~@+;&8_0#`k@u|gBP{Q-WC(fQ;Gx z?Zl-Vu-{&JBL~Z?Q03)UwbvEwYVd4}eFH{c<%k+P_(lIC&JKw5&*b{$SmbcW|JlH% zv^xI5Qd|ZCndvd*QGaAV^(+7K!8}gTkFmPQ=#8Wy?>Dr1c%SjJkU1Z^8Ov-Q&(rwb z-E|HBe6Y70t9J#b+j@4RIKM(KEMn!D_7U$lwX_T*@E$?h!@cvw_>?}!EAPIg!S@yS8u`HlGT0f_fP~aBU)&ZYuO#Ax zBek(=YT#!|?NTHX^_e9`jBTzdVN%$yX-~fI4#g#vBupzPm6AM^_O7z{Fn~6ladn~tEdN-_{kmfox(%!racThAM z>uLvBj0RdbNurfJ8)fNkt=4$OL$CI_=}FoPxBdd;jNAE5wsVL#cENsLXj@6@LG?bP zeHc8e#5Rh*1LEthm?|Ahh`m%%Iix-?uzEN9KlR!WiIxOQZ+;zAV1sIO(aW1qT1V;wTQYAjcK%V(e;4`2Ge z(c~H#J8W@?lH@4-sQfy|vX@HGtI;R?P!^Vg4ml`jy;OuN*b;&w7wSHF3F^K|^Qmp% zMIc`j6~ghyJ|C~1%9m`e=796$s!F#zh+l=ZtV8=wv9dbsRPpBPL6B^Wt}#(-Xmu<< zUg@QnOJQg7F8&KZ3QkGEuWYP2{-ubg6uYX}LR3p^=LRM|+fi(Vc^S<&o$*TTA2$Q4 z%z`8579a478!geO1UE!kTJSd-ba?&_?j319#ol5+<^9CL^>WzdCDUx-JM9>&#jYag z&xmBW+m_K0GZT9Lq(nqB7<u~i}N&vpEd!4UW1#ieB4gLOBZklz^VxkW_duP|c zzV($NBrBvIuuLS_IKqR^p$P0mYG$8RZNuDE74~Z^N2&VT&>n>bOA8jzIdvgd79j@z zMlN6E^aGT#1AN{hv3o8HGT@$EWSst>`e7lP^T`l4Sx&MA8KOlrZua-Wox0IE5B}VuoXA9(+ zEBT&(Gm%Pd5Kn7C=M$4|Xon(1ovaX#>31&L$O$+!0bVOdKFcS=+&PQpZv;uN3Oygw&9@Os#q%y^BaKR$m;OU^gco`^QQ_bv~h?GAmn#HA8B zgR#-BStYtz<`@vjdcmg;pAVCB$5frNgU0Tc<;D2LrTUmq98<(3SQ?A;@m4+?)M%fV ze(T5Aom$xwFa+hqC=a{@xT1m7F=&$6jl;{iNv`A^PsxLh_Px_SwS9}O<+MH0>5HFQ zkUQxa`})CPo#3l)M?pD@jZf9kaA+x4Ge(7PioU6O?Xl`Egp=osBQ4V5bXqILFPQx* zu6RuHb;(}xAHT57!%e1`ZFB3y3jB`BlqiQt!76voR!Q_FHJMb+^)d$!_K0Kr8hQgH z?X07)KE9@LR4k9J*)oDL2yPEd3%bz6!9&e)G}T1gyyxJ3EY zMv{2_%-H3}!HjvJRW(-#YoOp_lV6>^nQ<#XdrT`^Z8zECr@mm?syJ{Rmf`zO;H4bl z@P2eq%dblbcUGB(ah#$7KFxwk(ic7MFRXV0s99i9@DMMqMv2ROlcap@-SW$%CHejs za|pTa(2?$LS+FAAUKLCFMl9dll;yo`sH^_q+d&4C!QNqp;o2Zt_py zc-te)7;`E|frQuAfp6wpkkjC~3u6Au@smQkTBVau0h-3ztFn$6&->$a)YG?Vg=As- z)y+SWux?%wjE*QEengTcB%L(9WB%w{5s$j4rCWUAJWtP*V66U2DQ4$V5LNVEbxrT9GIo!w&)6h*%3o2L9NpPNoUhVp-x!0mSwR`(X9`ETm z<0_=Iy!R8shwhJ?kq@A>w7w-j`k$w*J(8N*b8^BkbrMmU`fVmqvdv}$dy*)F@Ks_T z-S3#d;N0dK&HG&xdt@Ja&eWGQC&&IVJ%V|22^@tAWK=F?TQ+#?p9GPwWKsyLxyRl5 z(9n|4V!`7_6hsSRP+*KYrTJC@?cMr{`n&na!I&$y>JUyjl|Zv_{z&fjSH6%%ra7JO zQX!zu#1FhFrnoUkUijB9Tc$H>bfSs=oCL-|tI1z*)WW!KEy!k6C1s`4$887N7KK9^ z%I$VDW|;aL@yrDIiD9Th(SWxbZgqbSr+ApLVCy?@(1lb^#>`rT6wWF)xAnY|%0k<_ z#XM3eKnsD^YvKK9kd&LgdU}d);Z91V^XiLu_E&Dz5}66#+bn=k&6kT2WhaDcwh#Sw zRMQL!&54QqN4SzKa7x3*5y=BOP_AjEg&o6wN09$(oG7>gA4$6+Fzwz6f%T(J9`AT! zZ^{$P$-rqJgPRAm?rzt!8>F#PV!xDr+m4S0=N+*;&y}K|iA9JN)i#+?W^`&ZPfSaa zc0Vof=9+Oorpk(nnH64-uu0;^TD#v8B7!7Z?|Wrz(=&+ZLd7GO?414WHZjRMK#-Zo zSX31f9uf5RftE!~uC}mzcu;97iqfe~u83%_W+0qc(^Nz~AZwl;<-7Z9xYA&0; zpaAS4|DG+@doH34jw0D42{at&v;4z3ZIHxax#W6+6 zE2n{N>_JoTTbt;8aR!CHs;*bx0rWY{<+3XI>r*@Q-pk)$uyZhU@1&GqUxe89F-2Z^75iP5%`e*(o!L05=(gW zm3arVTJ|14Y(|9HkO5Y|eve~^aZK7^2a)@3E+UYfNQBD-eN_MWdkj?er-sB#@0>e; zLrA-y5u~Vel9AFS7+B#)8p4O@%>u8<>KCFTDptC36_?OG9u3L+Ua6^8=FT`Ny1i75 zzS_pidJcQq&7sX~tZZvE@J56ckS{5#@K_5({b*x4R*FoIq>WCGM;Ne>NRn+6E<-gx z1A9EG1$kN_Mn&ABuo&I{(D0lrBY2p>BykobW)_~1UUs8Tf5SYyYp2PaD5(*qr1mw> zTbZ^0OrxhHhW8|JfGnp7OH%LV@VTmbnLt+ALqi@9*$Z|l?aPO30CA&?`#l{q(JwSW zU-qbXnih{mX99^>>xgn=fgE`gn%;9wmE6M%A6g-HmpTd{o)%uK1X#WdllV?`X2eHd zL{vPvWIN-Oy^>0GamFG$NKxeEaq|8^dSKMRpu=DW`he2F$2m zC2f{akP+sxUZqanT$|HweW)VuF`WP(5iaf?wU#9(Ac_5ZQSou`_bAK8FM>=5A)~A? zCJCaCH-hAR#(wWV7BIGiQEXe-XnBae-3c!YN2_NmB`CqIaEMCtbqlD`^Fl<0lKk>0 z>vLy|@7~U~*P6O&OHv(lV;Ft{bx*_M_Q=1u3L~$Hvj5Z#8FL2)(X4IdjpHwROWL)( zGFJ{f{NgJ5GFBdx=nx(-b%n#&W2v~Ic0ip?!~X5aB z-z`N{Y73*4f)hq_iZx_YtDQIYc-+9z?PM9NexI#AFsEECC2pFbHL>m>XvOI3J0Ovb zE5Q_&SoVm$iC4NCxoT3MzZBtjSD(+siu4_*?Sr&2G;YhyA&)Hmj>mLPIyed@kE~(-*#hCY;RlDSn?Y z!okbv)aMHh@LORf>*so!eVAtEIvQI4K0hqqHFkm}WtgKZh0s}7z}l=AkzLiv_kFsj zCh@J8ERJ8@lj8NySIC243kJSF^7yh#wh8Y6f3sq_ZfetV%Vb90M9e8;)Mh{m;_FigKx{KO@!y-qf|)Pv<)jF;Udk1#sMuRuhf!m1}?--|v# zVxfKP8GXuo&vM|G5TMZ3Vol%8J`3QP*k54`UyKah25h_A_;-Ksfs;zxZ>AL=@Qj|Zq0#wD-*64pN?~4SIKt#c}&^l8UYQyMrEZc%!m1Px! zHm`hqNlt1tM@1i443UUAMU&z@y_QOil&ynBK!79eWz+}fNrZ}!OT`}RfB`2h)fe=l zH}t{{v7t&-ARrBViMAatWmQLj)MZM|)9V3pmF8Me*dF~;UD=dK*FKX#gL$^ZuK0c- zWM6Um%Gs^ok{9KHSjp;}!j0?;)`is6XNk0aAA67B-&tQRc1i~bMly9{VLse{4P!zS z_yxn*b&$J|S0PEX#NaaNU0scrvn5B$ek$5$`A*+NUi_X<7U0gps^ZIK3R6tKiKI$F z4P$)16Bh}5INeCV3b0Cu1uU4RC+@Kq5FyzRH#CNlt0~(mwcZ~G&p*}ZZ_H?`xh;C= zc~9i+$7%br*H5go$QkF8+M~*>Nx0UFygArq0Qsbo+qySoirk=e5?*s_)WZtsX$rD5|vShH}+nr9n$SHyOCj3^O#(Q&4aUT(U!pKZalkz1Vz46O?`mlJ1YOAek^k zXT32T&7!_tCBoXnV%BfIAkR8|)IJmTzjj4M|E&o(6L1YvxBIjFYBFGZ%ip4tfGGx+wK+0#bH%ksj6wwgKEE zZbmV(;6jGMN2lRcT_HwL!xikZ*R9ta$dj8ZwP^J;0nTF}R*we5+{Lbv=myCta$5Ti z9B3bY9(89tyf~uc2WONW#1job=L;m z-6BGi5gC#6OZn|3qan)9NOqE)kv)?NWhN^t6~AoC-Ydz-%H9dtl)b%2-Ouwr_xF2$ z-p}XtPr96Qu5qq)u5-TUfDmu5dyP)+MJVDTBB%ey;6k|omHfh)(JAH6QTC0QJ0@UC z{M>7PWfCz&$hT^bb`jgIvnzrTl8;lK6|t)`}W0K5~p6c*DD+ zr4|!wdoi={V7!uj=NO$@_stIrZb~wb0$loElk---hlsVwFY+C0Ja{>xsl$wcFP!os zv^_Xgc9OPMiBHG&yj>4t7k?UuP)^!+UApkjpFeR|j#?^}60Zej<5uk+z479!Nw8ED z-~YifyP3UKy-r+SsPI|dDsR#h|GNsUn-s#6^rmIi6HYJMm`GN&7oxv*aJo;?jGXIj zopET499l!>o#__s@x95%d~{~CURTZbHRH^aU5qm+q=z!n**`}rENGRB?7#<#6yRuGqm6g{DtM{fgp%;t#-|LW4eTk4x~z|JyEgHXX7`Ik zF%#Fd3YA)dXV%RoA;dwi`;WPF;$83Six{6uMAysaoVb3v)t7$7HfkiL=xaTu2x*-4 zOd_Mn6UobbG@oDL%w^L+UJWaJsPe@= zmHG|8B^Q-sR&n+*n?VgO9MhKpqr>ZS1vQD;`tt4Y>^_#mBSwe!6l#PCgLt7Q5q5L`f?|sy~FP+dgIdSD6K=4(ZEmcloI{S1e6K7pQ$apgwm;)Up>J=LFSaamw z!3CaC!3&D+92HCbM#-a3tw(5`yO&2eE&Dk>uX?Osl-W;-qQ1E-u7sGatd zxb2vgoy$vQ;fA8!^`%msnzs8fjU47w!DnG^hgRlQlh5BeKJ&ubHbKr~<_U%B{`LEU z3^S$Zx;FiHlwiPw$-tcu&Y|v%>c@UlE|dF3(bU^jRn6&5Q|9570YCIK;Vr;A}&XI0YOg*nWPj!BMrTW4_fS0K_zDir>>~gqy=B0e~a{f~gXHrAw^yDxJG-Q2Ow_+ceE)DmfrW-b;ZzNU-G<93r~i}jhxqNjkP za5~Z8Q-dQ9a*#|4nl%l1cPyT#_}*e3O3kF!QPMcZ$DCDmd-IO&At8jt8b3$NtNBsx zv?5PMNvD#hS|jXrXEf*N%=Px4U4ORq;%EYA3$rp^fmnk@_MPQ2lz6w=9n+zOM3xnV zQ;`t`)Q}fEs$8gt)u&7YFJ~;@!84mkowdJLaLZQ!ciYXUlBp>E2upq?U`C|1e#KF) z|NN8p8|uKmUt4b9J@(*rSvqR(NNjb)0yeDV8(}GI>Vd_lH>ZwdG%e?iJejg-x6ZD9 zsMj?b{dKCyxlHWXkl{nS!(z6~<^g9b(mbz!y4gdYecOkTgDyrw3nO!Sbip>w%Q!^M zd99AFx$ok&z*%Cu^?v7P%8uh{g_Wf9KehyqQ?R=2EH#{drPc2(5RzxZmb}e_%%i4L z3cT9bP<=h#%ED>d$*)kACpWF7)~WbzPILL)3R<+$rp(qNRc;V_k}1ap&3#j|VwqUX z$|e{j_V*(OjaxopkF#KJMm$cV<&6Uu$q>BY& zGE1k*4^iG_6}osoNEdu=MID2mbl%c4R`vNH;zDYps~T}xJ7z|SZSG<6E>(PSvyy*Q zLxC{qbH_>lobF%xHpGF|R+ai7lkWuiiMKYBQ#9c8@vKX*>gLh9$twBw67~4VlU3GF z3T#5AY@S`)F<6OkjaB)6Y-bsv?eRov^=@CfI8DjHXQ^z>Pf7O)+Rpwg6qPIjQ%;qL z!nteL*Qgoj>$ET3V|cV6!yPgZV!6kB*wpDlEVj)mzRuNObu-#2ZL#W2h>}9_$8{Br z=r!;W%c)%U!fmBH6?4=EH+#>gC5IFScX2&GtiLs2jzZa8K~UPXHh7nK-6jnvRQ#rI z1|Dr)bUa(P{8qwSLEw8Ziy8f!X3Hm6Kiz)JNyb%;8B!%g&O(y_UajMj+SC zFNoexd^v=iANcvoi{sZG)`8K|09WJ@+VnTJw+xTIV$ZEOc>PhK7&tYRACnZJ-%6ci z=rD7`n4oyuWJfULG)weEX!VN=rSlG%o7QG%=P`e2ew&`c=6LeMH??@B*dEsF`GLFGs+3a{ zEuL!R>+B=3 zVf&3-;TuzDuL{!%bqwVPDT!OM7?#dmzZ5&4RvY1OkTt!pPcUc9>A?nV@zx8ggyK)6 zPg7cAqNa|~Jxq2ryJu%ANqc==^rK`-brb2#`ECI% zL~{b!uSKwkx6GB^@>~o0$&-^`H2A5N>%H!)yEl?$l}p<^Lr+FT72e-FYIytM7wa!i zxGm%mv6DlFx714!BXYg=H#%gkb5mvi*lYa$GfjnosvoDH%5*vT6)ImvXc?U3pg~Y($=6 z!KG?I-*bWh#`S@ycbYzn(3aacKh7ZxHo^Hp*Fk$sR z)bWgbo_CWgYGEpd4cSY zx7-6F=G8AC?O7ZwB{^i&cQ%() z#Nx$9PW`x;Lw{7`__Yiq@Fsfkjtbr1HW$u}QAx)m(pksi7EjL_`OOTybM4@gauE~z zV)EVMX8SZ?Ec@y)!C}p+#C&{`WM|3;!s~N~FP*rvD2BK@uM&O{T-J~ruN>J~0nT6D z_%7<5;HJ;;`3g~np?fa1K~^&3mc?dB6FYa41%)gaYQS$SbKR(BwDjfGPDXaJPJoWy z6N+oz^GeaHujgdTcdmVSFk{`Lsvyl5otD{+hz+gN72+ABmfuI^xQ}lY9KthvuzXVM zdfip|iN-{-Au~7wFxe4wGNez|_|)V4^)2JC*T4B!iylI7w|0hf*sbbxGLAAH5{!Pe z7PHTnZ1VnVBA>jbZI*1vhqIe|u;7f*~@boU=9Y{MuWo!LETv*^#n zalPf$_wWPX<`O(F4179V>2m$q=eg*!obj$N2L(4Il*FXw-Bl? zaE>#6Evfs?Tyr`7q4(2fO=dQiXUfxdy7(9`6MA0%0m{pqYv26TS^0Cr6$eJGNP~xx z=5*z_+F9KfaLW(4|01y1*n|XtQ;6$T5A=MLd(c1H0r3V{Zd#_B@AJS%T}>L-NQwtE z99jsCe3jS0@-xVyUSXqg6MWaf^z=fP>=1(r$z)HO2Nl^)7@SZnS$T1^^R1=P!sL&} zMca^h^^Q}{Jv~mW8I$^78jf%!s2279D%4UnzP@sBk~{Q0`niF6Si3j(S?9G|I`6X6 zKC(PBK+Fp#d|Z?7S(><#V_ued-=90ysaX{(#gQ+3%^MMG_nOswwZSvi#_Zj>9M&@y z__P82mHDOs5NV1%Z|=lJOYsdNqU?tEPs;Uvw>hC2JBQa;>Q#?(iJ<^d+Gr~+ zeaHjP&-H~k>3}cfI!ZT;iE^wT!kgJYi#&Q%Wzp={`;s}f?KV}~gZaz7;mS=_N9@B1 zN@4-YQV8=YtGKY?T79OQh1(aVqgpal*NzNkcGangFU2e*d``%Z_M60wW~H7lnRc&B zeo(GsbJ|z*ln3EsV`l0N`a+v|I-ce7*}HVCKCeHxs(lUE!HuD1eAO=>b_xy-dd1qp zwPNGlBP_R;I(^*VTrhA(dg=pxmCoTVlR6`Hj=8*@s?O-j>GtfnEGnI?? z2)D$Ep5h2CC(N4GW|el)1!rZkimgm}ju}JbaboGlSH+Jv__uyswQxD-Gidc#X@a98 zL$^$D#!3VH$b!$C!4IZZH5hqh&DL+2PMJ|fZ=@W}ZE;wcM|bLi<#+LssA8{;fbOho znt_5#&8q!uz6^qtkYuz+VdM6DzG!DY;{)q;U*?J9)Vxpe2z&liF<%o^)%9PY6%oZ9 z3!;RVFQ3o3MyX{fqltZ}m6!}nWyl$uUQzmW!g%kgS2RxstFMohZGDLfCVC@|bpB|} z-JBo{6YdZGTD$z+{##(qY_+-)2*s1Ki8ANNA)66>rZ*Ivv$(gTv6c(3R6r#&;OJ}< z@3^#qj*)a`(#IBBId10=7%U&K)eYvI6rwq%(3KtcxmN{j}Chsy8M-- zRmCOKw?6Sk`_L{6Fl6?9;*e&%#9(i-z*-`uUhaS?$Q^A^PspP;G3TkzJm;H(|KO`5 z27a3=-%#@&uM_HbI=yDbG)}9tS|^7D$DeO5KiatLceHVE(@v^B%+ShcpCDy2$f%W* zvubic!O^SOxuVQZ%p*r${_sQv`kiGn^XY)UUJ!46Y#EVDQ%~`AoO9{i*v^+-1BUl= zo0D~{crwOCeJ~@2UePw&zKvsX-C_CE%9y~i{;9OUU%UaYsfrw06dom z;G>EB@>*Q0ucD5+?;Qw-2Im}SBWcL%hVyD=6HBAhpWg^r2`D4-5W8o!3mq&|LT%cv zb>9qhpIY2@*}p*@qBK0dwBx|AR$4TE)Gt01J2l3)ZSp~u;@Yxtd!?J^yXx0_%k^gu z1zFnX1!|q|rF0`_0wU=zCD97yE35Z*?1YEeuNn_k@m@WveXGsMU?SjMqyWO_AOVqgkqx6+RA9fNaoD;O3Rs^Z`A^1T9*}l(Vwh} zKQrq?>blKcF zmDBz4KKP!@r(4}#TJt6!m1NJ1j7H)XmG>=GYloGK$XK)Z81)6^v0KsaR|!R93wWyS z+T>qU(jgvNEA!8K)Vw&#B#^O*T$_A~(n&(8lFJMkddj+YJ_oAPMjG`hR3B>gVV(iY z_Hb~{&IsquaQry76xC*>!v2w~WICcjZ4S@*D0`68{98)f;f^C~Z%b~*A2ws3=g^(b zHE|Iu^Ut}ubaxr)GV*jpN6apDN>BdRY3}KW`)cD{!v~S+>Z0-V36-+mhrD$cd-cE< z5D%Q|yEnwPpDP!3#kr>)?;(xwQ|_)DFA|^m;#?(ek4RWV4!xVXsQ8t^-qNmkK1D`K zed@7C%$SVmJ>e(c?6tRICyvB(mI>4kUD(L|o;LHMFGIH{lOm&LUQ0%#--!{1 zT(OiFFfg^a(3{o0mO9^l@GvR=-o%Uc9j^LcWlb5{3Gy>%r#IedE4=sNUh~K|^X zeZ(6*&tG~@le?dm1C+!l>&J@vZK*4!P0fq0U9CF4?cM6YHBtDa=!e|*(Qv`g61Udn zk5cqT$Alt7LPAu$cB0b3g*$`tvln<1r_MdPOlPPSwcMAd<)}xbd?i@Qi(0QfmEQe1 zdvl;$`E?GGEg~p*e(g7zboWtctt#=4pe~h@I$N|J5ioQQ(ODb6{Geb|NjfQ{qH%EJvvR=c z^Pj?wuD+EYN}rv}Xtm%2L`@D<2W(e8V=d^qycE9}Fp)lmnuxHfw~%}iDpaV$LU(** z#QX#E{vYP0M9(#^jQ+d{<}xkCyPxN^+my3~y#^c;kqyqN4!IL-)|y{c60x1gJT2*@ zRF^(b?~OUnLfu+eGe>*qvsCO6sb#wh7ReLdYLTYuRWCZ_q`q~0C<^Fir7@`qyyJmN zyUTF8XFe-{l>M{*z*WL1N18sC!DmAExG5>we|jWK!nvB+Wtui%{fxrDG%0V;c z@K&jz?c3BfrUKW+L-!2__Ia^y*R=2kmwrfzYYoaN{e^PKi#ZW6m@R+y$SWLG$w#i4 zU%cf=)?+Opa{)JBL+WUm(WKZK>21{AI<-aqin?2` zc0Q}r-)RgtMid?!I__S^hwJ&un%X-xzvZO?1z2SU&~A^~RvBIZlRZ*NI6a)5(ur1h=-Dr5}# zvxP%;baB&6S?$&*yQ@@0K8NTvwyjCVZ?6ho5uL6XKL|wxOGbcihO{~R=HwP-Sm)-_ z2VHtvdUXuaE*^S;82t3EIv`O;tjk?c!`$*$(C!^k(&omE8hk2ML;0J7ljbLje5*#v z=jNCbpBOZ9J~$rn*593L>w-gSN#{OMZ0}C`hvo3^lZHLv*24}B3KWNG=H@=%GYhw! zy~a{98?9c7O|zY3_Y!+h@S6IatG?DflkvJX%ft9+ffI#G^xS@}JMRaO2Q?amA1EX@ zuBUC>{n0C5JlI>%UY4^`s@r0ABdC?Dcv3;3H*0oP$7rcry`E|+RX1%TcJ`2&`sdlU zp7Wu0MY7W5AB>h|d&C{=dooDpE)(?UfeHzY7Nr#2QWcSM&3DyOiBNHm7^0@{?`Tl$ zS&MBf(w@4sU1wk6Kl8R=h0mMPDY0yIo~f)aq$n#TG+fZ)MA_q_boO4sRJwwf1g#I+ z`ZEINw)t-e*Oz0sY1?t%<&m*7LdL_6h65fRFFYi~KZGD_yRM}e5u;4W8Mg+f4dU|7 z$V>?z?-Cr|mn36+grQ!}V>LU?VPAS#5eE6?#X`MYfee*K(|l^$Vw70(fMmx^QqSb} zn6<*`vNHS?&GrsaYj=-lL>HpYWWAZT>?Ieeh4H8}d|~q?wgD<~vQv_5rX&V3;oGEn zHG30RkJbac>pH`_wr>@O_(V|4qtJ#@Vb%A!R$?W8?R&>}&G~{q@jUs2v1se#n;j-m zsoA6R?)dg-88z);&a@5wv5W^T)hSYfM}_m9Up>gn2xD5fkQ9=UKE_w0FflsHmnLFn z!Kv)4z2njz%%02mT0FNt|3>SwOrZafG>aScoNt#r=fk3mY8V%@alog{b(!mnm>5aP zSiU;B^V-DgQ%8M?vzG1ZK{=Tn(ZzIQJ8>;U&b*uB$2sej!%n@TLCySg;j})Ab*%dL zW~&7TfyoDUx8}w@qZ&VsY35$2En35BIAtw`;@?=VS)g5}5gx8w_`gmh{kwtf(S@~Z&G11X9 z<6y4g9&~MSS5v^rpcSPE=PvrG6STA*?>Zc-7Y+y~bh=76DN8h-@9dePf0|bo*Dmo( zI8S%&?QDIWxSYWTWBJiJ!u6K^suZ0suB3^iypgHRc+c=Ci_~Tm>H8o{tWRgbC}w7Z zF2nrX`}L0ZHQf#kq==A=Ra)M55~?O{i1oF~`a*j#JBw{)vS9DV9nDb6_l?G_0maWV zHXY>z=h!M&Ro$^p| z5z{fB1RC&m2v^NHBT;5Sii*Y@hw@T8y)frw-<9FbdZ(qbW;G`igE*gtc8}bv74^+F zY5Vb+C-n|K9S%LLOYZH;AHcDY{IX!#$tb%G>L6#FPcl_ec>aJuTax!%_v^RZ*OG=x z2JRKOxqk7C+sdNMCZBe%Q4QOES}Nq3miDS`Y0<6YDxbD)&Zc#O%#llPUKF?A>da5w za?l;>N96~-Q#z}7LR5om!(C(8jkCSyWt&p+@YZ;+zZ$LTr_6#{BPCTg zHJPznxnC++O}Yn7H8+-D$hgzt^PjVM>I$7x$f+JL>y1)1 zdq19hLj9=FG=J8Rm+q|XLZTZ3E~rGk*Gf}cpCfv%AU$EjBtweJyi}5h#e2Y*2c z_pAd}L9cxJHGA(ptRH+iI%7K+82kL!z0jdMz27uq+Y7M_vnJ!=QP%49>^b4RsEx9X z6a|(!LVQ+rn?3pcSXb9%28YNV%1r{-$o!A#PJ+3p(<`Tu+T^$@NggAG^ao{OvymqF zjdgngdY}q@39kNyMS+zOue^juE+Ht}g+*WEzG_DAEGWfD>)T7H6!?7A}#TFqQJ zUDB&@td_bD^sh8ItLKSmO?aw2^P%@ocZy0M$p6xLR^;~GyM|m$8z}})H#Kt0RSS0J z?zlJY=vYo`e``lD9+)~~wqEk_qh@dW)OC5!jm;@kM{CEDJQH2gv847#jU2n>?unrv z+7^vbk_y7&gJ?pYRTv3BA7bBD6*%(l+ zVVBh@Ds`1>a2AZYJ$XaIAw(@;kdyFagW7JIaze&jUL^~GFI3++<^S~}o|P`T&G%~n zJyl&H16N*#qz`{sr1AvHFXZ3zz5YYg}0TwwJ#jPpq%y9xbOL7SVQmD~@SN2rc*eq~rTN!job=)cQ9tNSf6 z*l}=miq?_MaFbFpxM5-bp8H*KfBo1p;eiq{oSBr9DJD6;cFn`9K@%rf?XLU7lGc5b ztSZdz(!O*0m~b@Pq%PA1`$CL(8fB+6;`M#0!#)ebdFCgYoF3;`S2);YpDWXNXdAo} zvv6{0tWDsUaQ;)pMA!45FB#{^TXYY*sts5h@ONBT-XZPCh}H|0E$w;J?7Q#ER{hmH zyVT2OXUw{dxJ}jNwwdZ;sv0qGwkhN1V>B3#wzwO~uX?hDoMtZUYknG9YLM|#+$BB8 z?Wi;>LM2hLv3}6Bl3M=j=$27q$4R;~njvYn=#){@y2tU{3`MeQ8s|`W2Fmf#%oyc@ zk%hXj^O^*N*hw+5fd%4P8GGJlu6j>jlfKV;&UphZi zTD39O6f@;pz;J*=w+GqZJn`w?@`kGw)zFf&WS zT6WL08?&8f`_`zA-?$G-4k1bu3)9xje7OTIV+}D;l~1Lko}3QPx%c8C!pU{*(VF-> zQ+lezK7)H}+xfT7(5L@OzhZw%SWT-f0bGVlk#0}Dk!9F!J(N*Ww7oW! zQMTQ4&&ncw0}#t>^J~=KOpW$IVv<>BdgMw`3p0;(?ci(mrDWABfe&+XQ#Eo-mj>So zu3tJun#){QO}TlfpV8HEX%hT4p-o%m22LHE{rc9Rq^Ba*(a=(-XgQqw?n+KW?d~6Z z(rldKdRPz6rFZAq&(t}&ubW(Yyq7LYH6!xG`tww|l$&W9C6dFljpaXtMqNhmZ&3O4 zDtyQ_odWeN!yMTeYF3`Wcvpd{u(VqrTx*&5eZsGuQ+$2VV^ba6fgEvsV|lJO&vGN| z{7$5TpoEebB}D0fY1(=W&%bM$1!>n8iuI@`Z%I#P6^7o$?_x0xf{yROx*TX?TVBqGX zp0RL2wRG7xPgb9FWncM?qc7Wj#(Adm#Ge)wk?r;2f(|+@Po97~5`WWhA=_rACr2Z< z{^;{t_yW^U!QmmRamSAzpExdMZvpUc!{b+WW_9s+lzUfgdL zJfAaumgQhzd+YW|lhzBu%&pwN|8mMIX#P_PKkGqIZ6_R%?(fugGy#u}?s-W4gLibw zCP<6z+=ls0zO?OY#IGaZ)l+a?Xr)t~!vOY?-uuH{oU^(a<1R5tIeWqFs(UtTo$6K! zm-~aRtj?66cDfcng}pkkdmI0elP8e3I+KI%vK_t|*gVzS5wnKHi0uy67rhKlSMaeP z{CMGH9_u+`DwgZ_BM{LICP>{u_P2V?GcISV#H*IHTMr!P20bnwp?6uUyJ272^8Hsy z#g4l#I;WU!_Xz-=JEZARj_ciSD&G9VkGJP|=gv!1gG-I~9C?(bQ<~C4>wPJ-UvRw7 z-!NF{r!dnl@|vN<@QiZf2~^_1I=*J-%TDFqyRP65d)|;IM_p1QZP_G>UeV8sr?_ei zE?nIG1Mjn7ol+kH$E%4}_nq#Yj3vyU4tnJ4YmzKX437^v3EzbHyp1`?&a!RHFho;vZ9%Gg?DlPcZ#d(x(Ut4jyNit;^Oh5JBHtPM|pa&IAqS> zQBJQ*ef54oxPf6P=GbpK_urwo616h~4|9BW`QaFWihKL!;%*0CMuAZoM>$P4f{rfp z>RCgjE6N_ba0y=dx)oak?HgTP%dP?8$lJQV-wC0YtW(R$C`DDej3|Cf2~c?H^P5`? zTB-ELfkjWo4u;r+rG?+Luju_AiD1bNYS7M2Haf@SYktuPFYh1P?zhbnO7%$is=4~QfrLR{f=tT zdxE=XUhcbJ<%iA_MhVH-aGXA_MQ11B? zF{mBxd`!|}B5;3c;ep?`?(fl}j+$rYo>XNkpzA*NllOjp(r>}Pz1$UIX>5{FS;NmS z^LcBlFX;amHi$?0;nxW6%mqSX7{ z{EKP%y!irwDve72Ell5LaIGDy$YDP3v28j>@B!VfBrH7T*L2QK=&^Zplya@o{GqOo zCSo36*jta#;pL>UZSMc`u9YTlAF)JS*)V17S>U`Syw_Dv~^JryWdp#>D z$W`qNt>X>1tH=CDt{`{)C)?5NaAfR<0uJs2hOS+|-x#?l(HxRtq#YPX8dWSSSBpu< z9Q&>Hwud@m9AFwt364(3hSoCgkkJRANe-PGmBL+XRa!`X)N%SHttI2$S zCXkvuRbkPMzbXfgHaR=0l>45EDthzt_O4qzESwTK^iunD;$gSK+hkd3!K3Xd{IT{lc-_kxHzHTP7WoYR@a&EE&`=8 z`S3sb%yVY!alf@06Wym4tko&qp)x@>nk#%FUAxad>02+)msp$~-q@PiMXUEW+5iwx zez5seniih=rh2TgUvYeN*We!Sbpbaj(yPm6-S;>i%g*foJ7PT~dmwZNO}!p8`H8UEO1`(T5=GTz$EdR_iApSFeJ8Q;z*pDgBh`Rnhg$Ztgq>Z{USeLq(FUnXbU z9{1O|^RxMUdvza7rQLt0a$E&D$N{F3GDlVV=P{K%P694#>9Hn>Thm@;RK28#jz z(H@((;m8N^Ny~%uUsnIv(M9j0h{1=nhw)`Dx4)&(ce4F4y5vvb&4>dj!*qD}u_q5% zJv$^8u8I9E)H|U{rtx4dTdMv;-s`J=N|V*d!}wQrwet_vT0|VKyb0gs`>>DdS-mGo z)q{usi!b;VKxZ@#Pi>0=-aQ2qINs5$U{OAgm8EQfsEBgDjC>V+F9!x*zn*{yN#8Q|Ms%f-w!yUasTsr zQ%`FKO3|v8YR`edzf%5979=p-KV$)WnM%^q+WdcH@jv|X{9jK0mqr|!{F_E8YfC#T z9uX1bA0hw#FH)HYsbZ~XVPmCdZD67AguKpUYi(zMyaM172KFZU21-(w!RuE4FaGd2 z?Ei9@qb8Gn>gwUXPK0U0+uEHmnrr7sdrhAmfAfI$cE!>&>I+%P-k-i)d!5iZlV~lx zmA4Vd_v$bA<+V*xCEs#{#?ev_95;Cx!xXViT3p^-X#F*u@r$uh!TnO>pyT?{ZFljy zwS`~3zv_3&job(MmWFHIhJ@ z@u`&*3yc;7FT>6pIXL?xUgo4RldeLhK-qG7;O)oG9%EUGVQl7ANtxJ5za{C{JRL5?&XczvsZ@bm=Yf za!*6nMV^5DY>K>;r>P zlQW6DGQxe^@m?GyERR$pjC-#wuAK=wyU;@&C38oDE;N<+tab>eLP73G4D#?Ve z&qq!%H>|SMDEDcb4tyd>AGZ&`?eyB$@+|rszJ{bQj+vCC$f*&L!Utn8IJWy-i9cL} zM=m9ig%oKmxn)oACEYn4_@?IAgQ3ZE5e;Kh@bjOEhhIKwYZ!fV!7GRq7_Hf)Cy+*& zQS~-1IEGLUy|TFXvP<2^f=Es0mA~9BtMZU;btU`s965FBEcTFTe8A&RGKW50%lA%7 zdBOGl#F+N$=m8(;m+S7N`MrsJI-YuaxDS5iOl0d(H~KNOM_;4nCJ$XW?ymjPSaL-L ziJk0?>E4sW_Ppzkl6vvUYkjvXo6a|zWxkVFS76fNI?6j!&?Zq6?IT^9kYY(F8xSd% zHZe#JijX=n$`ihFQB+g4f_!FgTJ>iR?ZOc|T;@DIJI9{#G$m6 zyw|zjnzyopoRDg~er99BPY2_sbG4H8Q67ERmy4!SNcQM5|lcP*C-l-8Z;1QeQG;)WzSD6B^BSKwOzr5=MuO z@qf9(v`;BHji?+da?Y%yC-jqHbJ5We6IWeDqkB43{NC(GXW3J(-?%o_8I`_FNk7os z_9bg7eqGy*RuMdR%rw=PJGgl#pl-OMsJzc%;p_D|o#wl#%cGZz-7jsFva`jvtebqC zJFTwPGHT9H$TqCPnnU&=%lP9>Pn@E+q2f1Qm*BWDcgEDAtm4hdpw5SJy*3MLgj3ii zI$e(SCoZiE{GT}LU;jcZrTaZRVqBfo<0&a+ejq?PhbZ#K)JFYnZF@oGYE&c3uz-Z6 zy4N&I%+FqA$(M@uu!7Osmn<)mYVhlv+NTHQBWpE6gl;^Vvii!q72rzVXKHEOlkWAP zxiixXH`AHRqI}*=`$|oHPiOS9XG2R*%aM6|&2E*#k zO`E2kC*{+`7!&`Z^U-?;N6|{@?;q=$JbHQS#=6?M^&#E5gVM;4UteCL@ohdoZo}rm z^DU>%ss9{0z_N@Y<<-O@)S=&c?HdD=S@twLub#Eu3TwGAhee}ul&$lj%}P3Rucx{{ z24}r2eW%@PmKcsj`bqv=(5b$^`p2v{qzc4gNC3b&!EdC3_-~mnu3`+tm{1b-7V?ka4 zff09ejeo*$I6N8#BVY*-7#c@FL-C^VXplbrb38O2LjuXzKX8Cn7z_-C$HUu!hbm$1 zK-L6B#>b9K_uZ|av_q*u)ZWToMw=q!uSBg!Du1jaq#g7L>Mg~ zqlWQIA`@V8A){eBjwXW_OQHOd;d+WD6X0?olhDxl#h_3)s2*TY7$TH63<{Vd1TO|f z#K6Y``8=#088#mnG#X|z7&HbC8xIW@8_@B9(ZJ{f3Io+Y44RCF$`pe^!Sob^f%^>% z28V&p(QY&7cvxT`P`p?o8Uv*nOT-YMa>f#IF#51WJWPIAB4O7J|HCe^L=w!0VToio z4iakD5C5|-2?MifED3M|Ylnx;5tc-N=?0cW!oYEmVLl8?M#20amW)BePi$kGcd;qN?Ky?j=!oqAChr+?;1BW7@p!DHTL>Rv~6kPvsXcU}2 zGzMmaI5Z9e)fXI^0Q2`a;Krdo2M3%442D6G;4rY#hsp|rh0}+@qoDH(s3Sq=1BW5O z;tURpg5$sfD}>_30`6ci0?a;uwZZ2NC=qPVasR?E?qB4L0}Y{gad;w(J{<91+L3T@ zykruL4?G$!13cUx;P61RptRuO{s54NhWZzvr7-)&;mNztbN|EkL8=1t**F3Q7JG06 zpuMoZ@Vo>^AfjM;^)GQBMkv##6g83W*78p9T z9moZszG+wV&~`+SGC$j3YJTeh$L7Z3sNpvOeT?VFu4E?g84rZi44n2$Ur%uegi~2SeyYpVeZZ2-OXsxv=~hz_3_|J_8s54V3{1$xxdCN{WX1L;wSh2*Ml4nut){ z0QoMw9R`-mqd^`E)jt4(#WFO=5}|7$00T+{r3DL%jUb~z!Q0`m&@~Bg&IByPjsOg{ zUO)p5XDLG}%i0T$RG)E2N<*qROq z6qa`a7!I0802o*RLveuO3k)wF1E&v!X?R}})Q6$5KqaBJ04xR?k3b_>z5!rl=sF4w zTnS8mfHi2&58AqM5&ymnLkPpGzkzjm)a1PT0kkdeG3ZQgDgsx`*j103a zJg`BiP2Y+!V6_o60Sk-M0QP(T>wj}h03$;412o9iU^WAm&M-ej0Fwmu;{+TT z=1&QD3^ae)-LQn_LjVSkJp=*@7NbBV0~Q;Jz?ndGjfe%SM9BOSf&YWf2Pjp+?1Kmv zNU(Nb(-SrxaQCowpq>bo3lR^D3rY(f6cwPbT?K@}u&}sK!oYGzpjBWe7}A%7A;ad9 zgarWv+763{t~t>pED5ILBpetJ+7~Qnp!NaMXK3vZO#%i7>x&1@6FMGniLmhqU~vy^ zN5DdBBfHrKw9WuvKw8kgz>J`HK{Xb-J_ivB2lLrvu(=GSg^U9UGz143hlTk%GFZSt zWk3cfp!9)VdYGPqJeCZNTOf~x`9CtS8K@qB5+h7^K?Mq0rvXL;xP$UR1Q`bmhKJ_B zAmxIsj{pov@SlA_0tbsJyD1k`&Hx6S3A8VP2=&>Zvo7h(|CSApL{21Bn=HJS^BJg5uaM6hdLZ7sGJi zV0ArEr~-x#=?jDfwQ~%JMo?c2U<7E*1Hj0z`Nd#B77WD!N-|LTFc`2Xfwse9p!F~? z93E=Z00uS_pnY)|I3FMcz}vxU&0q-ut0Msz5GoW09z;&{zg$7q-6uVBp{r ztS=rW7oZt1e}zSXC<^Th3>|78STsmlVeQ~@#)3mmQ2hg83+9`!AlkxlkYRR&-CdkQ z@nT?c6(}E2B3L_62!X+1@d)%K!)zamh2?bsE3D=VU|?|y#Q|I*90oRWVC`V_E3hO+ zL1X;yWiqTUSTsTP6qIw|a>fziw19XHn@c?0w}VO~%$I=eZfKkaF5>r2{{QCf07ihz z6vR~+&3JGk5Goh2fq6A`a||Kw(6%Ndy2k8sM3|*%H@!_C(Cl)Lrpmhtd4F;;Jknwt8kO9N?_W_Iury1m;5P!dGmCzg*z+g2purdWM0ZI!I7#9pi zfYu(s<`E8>n*kWC9=5v`2+c783{;IEIM66OG?oFWz}6aI5f2J+(7wRkL;Nn-V8+2@ zg~kw}wKsj0WK4S+)C!?@5{QOrHBx(K+4Za&y literal 0 HcmV?d00001 diff --git a/audits/README.md b/audits/README.md index 40098a44d..c629f51d3 100644 --- a/audits/README.md +++ b/audits/README.md @@ -2,6 +2,7 @@ | Date | Version | Commit | Auditor | Scope | Links | | ------------ | ------- | --------- | ------------ | -------------------- | ----------------------------------------------------------- | +| May 2023 | v4.9.0 | `91df66c` | OpenZeppelin | v4.9 Changes | [🔗](./2023-05-v4.9.pdf) | | October 2022 | v4.8.0 | `14f98db` | OpenZeppelin | ERC4626, Checkpoints | [🔗](./2022-10-ERC4626.pdf) [🔗](./2022-10-Checkpoints.pdf) | | October 2018 | v2.0.0 | `dac5bcc` | LevelK | Everything | [🔗](./2018-10.pdf) | | March 2017 | v1.0.4 | `9c5975a` | New Alchemy | Everything | [🔗](./2017-03.md) | From df3f1fc4db6955d0fe4736b6c43d4861b7436cda Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Tue, 9 May 2023 16:37:25 -0300 Subject: [PATCH 124/133] Specify changeset commit manually --- .changeset/tender-needles-dance.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.changeset/tender-needles-dance.md b/.changeset/tender-needles-dance.md index d75adec95..04d1784a4 100644 --- a/.changeset/tender-needles-dance.md +++ b/.changeset/tender-needles-dance.md @@ -3,3 +3,5 @@ --- `ERC20Wrapper`: self wrapping and deposit by the wrapper itself are now explicitelly forbiden. + +commit: 3214f6c25 From dff520afae768f1e94471e1ca4e08293d4d8e159 Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Tue, 9 May 2023 16:53:55 -0300 Subject: [PATCH 125/133] Specify changeset PRs manually --- .changeset/beige-buses-drop.md | 4 +++- .changeset/curvy-shrimps-enjoy.md | 4 +++- .changeset/curvy-suns-sort.md | 4 +++- .changeset/famous-rules-burn.md | 4 +++- .changeset/funny-rockets-compete.md | 4 +++- .changeset/gold-chicken-clean.md | 4 +++- .changeset/healthy-squids-stare.md | 4 +++- .changeset/lemon-dogs-kiss.md | 4 +++- .changeset/little-kiwis-ring.md | 4 +++- .changeset/pretty-hornets-play.md | 4 +++- .changeset/tame-ladybugs-sit.md | 4 +++- 11 files changed, 33 insertions(+), 11 deletions(-) diff --git a/.changeset/beige-buses-drop.md b/.changeset/beige-buses-drop.md index 4566eccb0..ecfd08b35 100644 --- a/.changeset/beige-buses-drop.md +++ b/.changeset/beige-buses-drop.md @@ -2,4 +2,6 @@ 'openzeppelin-solidity': patch --- -`Initializable`: optimize `_disableInitializers` by using `!=` instead of `<`. ([#3787](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3787)) +`Initializable`: optimize `_disableInitializers` by using `!=` instead of `<`. + +pr: #3787 diff --git a/.changeset/curvy-shrimps-enjoy.md b/.changeset/curvy-shrimps-enjoy.md index 4bc410abf..22c2bc54c 100644 --- a/.changeset/curvy-shrimps-enjoy.md +++ b/.changeset/curvy-shrimps-enjoy.md @@ -2,4 +2,6 @@ 'openzeppelin-solidity': minor --- -`ReentrancyGuard`: Add a `_reentrancyGuardEntered` function to expose the guard status. ([#3714](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3714)) +`ReentrancyGuard`: Add a `_reentrancyGuardEntered` function to expose the guard status. + +pr: #3714 diff --git a/.changeset/curvy-suns-sort.md b/.changeset/curvy-suns-sort.md index 97b51fed7..201f45ca7 100644 --- a/.changeset/curvy-suns-sort.md +++ b/.changeset/curvy-suns-sort.md @@ -2,4 +2,6 @@ 'openzeppelin-solidity': patch --- -`Ownable2Step`: make `acceptOwnership` public virtual to enable usecases that require overriding it. ([#3960](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3960)) +`Ownable2Step`: make `acceptOwnership` public virtual to enable usecases that require overriding it. + +pr: #3960 diff --git a/.changeset/famous-rules-burn.md b/.changeset/famous-rules-burn.md index a746dc21d..a97aca0b3 100644 --- a/.changeset/famous-rules-burn.md +++ b/.changeset/famous-rules-burn.md @@ -2,4 +2,6 @@ 'openzeppelin-solidity': minor --- -`EnumerableMap`: add a `keys()` function that returns an array containing all the keys. ([#3920](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3920)) +`EnumerableMap`: add a `keys()` function that returns an array containing all the keys. + +pr: #3920 diff --git a/.changeset/funny-rockets-compete.md b/.changeset/funny-rockets-compete.md index a8c77c619..3f665bc9e 100644 --- a/.changeset/funny-rockets-compete.md +++ b/.changeset/funny-rockets-compete.md @@ -2,4 +2,6 @@ 'openzeppelin-solidity': patch --- -Reformatted codebase with latest version of Prettier Solidity. ([#3898](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3898)) +Reformatted codebase with latest version of Prettier Solidity. + +pr: #3898 diff --git a/.changeset/gold-chicken-clean.md b/.changeset/gold-chicken-clean.md index 0d64fde6d..1353e9c9c 100644 --- a/.changeset/gold-chicken-clean.md +++ b/.changeset/gold-chicken-clean.md @@ -2,4 +2,6 @@ 'openzeppelin-solidity': minor --- -`Strings`: add `equal` method. ([#3774](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3774)) +`Strings`: add `equal` method. + +pr: #3774 diff --git a/.changeset/healthy-squids-stare.md b/.changeset/healthy-squids-stare.md index fad0872e2..9e2c9f3dd 100644 --- a/.changeset/healthy-squids-stare.md +++ b/.changeset/healthy-squids-stare.md @@ -2,4 +2,6 @@ 'openzeppelin-solidity': patch --- -`Math`: optimize `log256` rounding check. ([#3745](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3745)) +`Math`: optimize `log256` rounding check. + +pr: #3745 diff --git a/.changeset/lemon-dogs-kiss.md b/.changeset/lemon-dogs-kiss.md index 976949d2c..5e2787cf1 100644 --- a/.changeset/lemon-dogs-kiss.md +++ b/.changeset/lemon-dogs-kiss.md @@ -2,4 +2,6 @@ 'openzeppelin-solidity': patch --- -`ERC20Votes`: optimize by using unchecked arithmetic. ([#3748](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3748)) +`ERC20Votes`: optimize by using unchecked arithmetic. + +pr: #3748 diff --git a/.changeset/little-kiwis-ring.md b/.changeset/little-kiwis-ring.md index a1cb7bb95..81909a513 100644 --- a/.changeset/little-kiwis-ring.md +++ b/.changeset/little-kiwis-ring.md @@ -2,4 +2,6 @@ 'openzeppelin-solidity': patch --- -`Multicall`: annotate `multicall` function as upgrade safe to not raise a flag for its delegatecall. ([#3961](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3961)) +`Multicall`: annotate `multicall` function as upgrade safe to not raise a flag for its delegatecall. + +pr: #3961 diff --git a/.changeset/pretty-hornets-play.md b/.changeset/pretty-hornets-play.md index 230a53bb2..e7d15c24a 100644 --- a/.changeset/pretty-hornets-play.md +++ b/.changeset/pretty-hornets-play.md @@ -2,4 +2,6 @@ 'openzeppelin-solidity': minor --- -`Strings`: add `toString` method for signed integers. ([#3773](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3773)) +`Strings`: add `toString` method for signed integers. + +pr: #3773 diff --git a/.changeset/tame-ladybugs-sit.md b/.changeset/tame-ladybugs-sit.md index 8a1e416de..4cddc219e 100644 --- a/.changeset/tame-ladybugs-sit.md +++ b/.changeset/tame-ladybugs-sit.md @@ -2,4 +2,6 @@ 'openzeppelin-solidity': patch --- -`MerkleProof`: optimize by using unchecked arithmetic. ([#3745](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3745)) +`MerkleProof`: optimize by using unchecked arithmetic. + +pr: #3745 From d095542fa4e35212e822fca1df166211f9b68186 Mon Sep 17 00:00:00 2001 From: Francisco Giordano Date: Tue, 9 May 2023 17:36:33 -0300 Subject: [PATCH 126/133] Disable code size warnings on exposed contracts --- hardhat.config.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hardhat.config.js b/hardhat.config.js index 639e10f95..5fd703d06 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -76,6 +76,9 @@ module.exports = { }, }, warnings: { + 'contracts-exposed/**/*': { + 'code-size': 'off', + }, '*': { 'code-size': withOptimizations, 'unused-param': !argv.coverage, // coverage causes unused-param warnings From 9a2e4cb3a71326bc91a177f7b1f184448ccc799f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 9 May 2023 20:59:22 -0300 Subject: [PATCH 127/133] Update codespell-project/actions-codespell action to v2 (#4229) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/checks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index ae48e9286..1f03aa38c 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -107,7 +107,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Run CodeSpell - uses: codespell-project/actions-codespell@v1.0 + uses: codespell-project/actions-codespell@v2.0 with: check_filenames: true skip: package-lock.json,*.pdf From e5dbc7435e5995cd539d49fe51a508b48856da64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20Garc=C3=ADa?= Date: Wed, 10 May 2023 12:59:11 -0600 Subject: [PATCH 128/133] Add final PDF report for v4.9 audit (#4235) --- audits/2023-05-v4.9.pdf | Bin 483005 -> 485395 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/audits/2023-05-v4.9.pdf b/audits/2023-05-v4.9.pdf index e7e6d715b04b0fffb92f424b63120a01e2207f72..21cd7f59307483e93957a3b2c94aa11c0efe40ec 100644 GIT binary patch delta 257244 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%0AkFbk-zM@;TDwre>t|o-6^}I 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 z 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�%Y5@MSyC#8E-c4W=h3xls!eWGApPoE(_giI^5 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